ㄱ.   new로 생성한 것은 객체에 대해서는 유효 범위를 벗어 나면 스스로 지워 지는 것이 아니라, 직접 delete를 해 주어야 한다.
- for
문을 사용 하여 delete 해 줄 시

    for_each 만큼 명확하지 않다.

    예외 안전성이 갖추고 있지 않다.
-
포인터 컨테이너 대신에 스마트 포인터의 컨테이너를 사용하는 것
.
-
스마트 포인터 사용시 auto_ptr은 피해야 함
.
- boost
라이브러리에 있는 shared_ptr을 사용.


class Widget
{

};

typedef std::vector< Widget* > VecWidget;

/// for문을 사용한 해제.
void doSomething()
{
	VecWidget widget;

	for( VecWidget::iterator it = widget.begin(); it != widget.end(); ++it)
	{
		delete (*it);
	}
}
/// for_each문을 사용한 해제 - 1.
template<typename t="">
struct DeleteObject
	: public unary_function<const t*,="" void="">
{
	void operator() (const T* ptr) const
	{
		delete ptr;
	}
};
void doSomething()
{
	VecWidget widget;

	/// Widget의 포인터를 삭제 하는 것이 당연하지만, 실수로 Widget 외의
	/// 것을 할 경우 버그를 발생할 우려가 있음.
	for_each(widget.begin(), widget.end(), DeleteObject<widget>())
}

/// for_each문을 사용한 해제 - 2.
struct DeleteObject
{
	template<typename t="">
	void operator() (const T* ptr) const
	{
		delete ptr;
	}
};
void doSomething()
{
	VecWidget widget;

	/// Widget의 포인터를 삭제 하는 것이 당연하지만, 실수로 Widget 외의
	/// 것을 할 경우 버그를 발생할 우려가 있음.
	for_each(widget.begin(), widget.end(), DeleteObject())
}
</typename></widget></const></typename>

Posted by 냉동

ㄱ.   단일 요소 멤버 함수보다 범위 멤버 함수가 더 좋은 이유.

    범위 멤버 함수를 사용한 코드가 대개 짧다.

    범위 멤버 함수는 훨씬 명확하고 간결한 의미를 전달 한다.

ㄴ.   단일 요소 멤버 함수에서는 메모리 할당자의 요구 많음.
객체 복사도 빈번, 불필요한 연산도 자주 일어남
.
같은 일은 한다면, 범위 멤버 함수는 이 보다 효율적.

ㄷ.   copy를 사용하여 루프 없이 비슷해 보이지만 범위 단위로 동작하는 멤버 함수보다 비효율적인 면이 있다.

    불필요한 함수 호출 범위 멤버 함수는 한번만 하면 되기 때문.

    새로운 요소를 넣기 위해 들어 있던 요소를 밀어 넣는 비용.

    메모리 할당.

ㄹ.   범위 멤버 함수.

    범위 생성 모든 컨테이너는 다음과 같은 생성자를 지원.
container::container(Inputlterator begin, Inputlterator end);

    범위 삽입 모든 표준 컨테이너는 다음과 같은 insert를 지원
void contatiner::insert(iterator position, Inputiterator begin, Inputiterator end);
연관 컨테이너
void contatiner::insert(Inputiterator begin, Inputiterator end);

    범위 삭제
iterator contation::erase(iterator begin, iterator end); -
표준 시퀀스 컨테이너
void contation::erase(iterator begin, iterator end); -
표준 연관 컨테이너

    범위 대입 모든 표준 시퀸스 컨테이너
void contatiner::assign(Inputiterator begin, Inputiterator end);

 

#include "stdafx.h"
#include < iostream >
#include < string >
#include < vector >

class CTest
{
public:
	CTest(const int _kiID)
		: m_iID(_kiID)
	{
		cout << "ID : "<< m_iID << " 디폴트 생성자 호출" << endl;
	}
	CTest(const CTest& _krTest)
		: m_iID(_krTest.m_iID)
	{
		cout << "ID : "<< m_iID << "복사 생성자 호출" << endl;
	}
	const CTest& operator = (const CTest& _krTest)
	{
		this->m_iID = _krTest.m_iID;
		cout << "ID : "<< m_iID << "대입 연산자" << endl;

		return *this;
	}
	~CTest()
	{
		cout << "ID : "<< m_iID << "소멸자" << endl;
	}
private:
	int m_iID;
};


int _tmain(int argc, _TCHAR* argv[])
{
	CTest TestArr[5] = {1, 2, 3, 4, 5};

	cout << "=====================================================" << endl;

	std::vector< CTest > VecTest1;
	std::vector< CTest > VecTest2;

	VecTest1.insert(VecTest1.begin(), TestArr, TestArr + 5);

	cout << "=====================================================" << endl;

	copy(TestArr, TestArr + 5, inserter(VecTest2, VecTest2.begin()));
	return 0;
}
Posted by 냉동

empty는 모든 표준 컨테이너에 대해 상수 시간에 수행 하지만, 몇몇 제품에서 구현된 list 클래스에서 size가 선형 시간에 수행 되기 때문에 컨테이너가 비어 있는지를 확인 할 때 empty를 사용하여 비용?을 줄이자

Posted by 냉동

ㄱ.   STL의 방식은 복사되어 ( 컨데이너에 ) 들어가고, 복사 되어 나온다.
이런 복사는 해당 클래스의 복사용 멤버 함수를 사용 ( 복사 생성자, 복사 대입 연산자 ).

ㄴ.   STL의 기본 복사 방식으로 생기는 문제점.

    STL의 기본이 복사 방식으로 이루어 지기 때문에 데이터가 크면 클수록 메모리 사용량과 CPU 사용률은 더욱 높아 지는 문제점.

    상속된 객체의 경우 복사 동작이 제대로 이루어 지지 않는 형상 슬라이스.
기본 클래스의 컨테이너를 만들고 파생 클래스를 객체를 넣으면, 복사 과정에서 기본 생성자가 쓰이면서 파생 클래스 부분에 선언된 데이터는 잘려나감.

ㄷ.   해결 방안.
객체의 컨테이너를 만들지 않고, 포인터의 컨테이너를 만듬.

    속도가 빠름 포인터만 복사 하면 되기 때문

    정확 포인터를 이루는 비트를 복사 하기 때문.

    슬라이스 문제 해결 포인터를 복사 될 때 잘려나가는 데이터가 생기지 않음.


이렇게 포인터의 컨테이너를 만들면 인해 메모리 관리에 대한 문제점이 생기지만 스마트 포인터를 사용하면 해결 가능.

Posted by 냉동

ㄱ.   STL은 일반화에 기초를 두고 있어서 컨테이너도 일반화로 만들려고 하면 안 된다.
, 각각의 컨테이너에 공통적으로 있는 알고리즘은 사용 할 수 있지만, 각 컨테이너에 있는 좋은(?) 고유의 알고리즘은 사용 할 수 없다는 것.

ㄴ.    typedef을 활용하여 좀 더 쓰기 편하게 하자.

ㄷ.   컨테이너를 보관하는 클래스를 만들자.
변경이 필요 할 경우도 있는데 이럴 경우 바로 사용하지 않고 클래스를 사용해서 관리 하면 좀 더 쉽게 보관 할 수 있다.

Posted by 냉동

ㄱ.   컨테이너 구분.

    표준 시퀀스 컨테이너 ( vector, string, deque, list )

    표준 연관 컨테이너 ( set, multiset, map, multimap )

    연속 메모리 컨테이너 ( vector, string, deque )

    노드 기반 컨테이너 ( set, multiset, map, multimap, list )

ㄴ. 알맞은 컨테이너 사용은 언제?

   시퀀스 컨테이너 사용 할 시기
-
컨테이너의 아무 위치에 요소를 삽입 해야 한다면
-
컨테이너 요소들의 순서 결정에 직접 관여 해야 한다면

    탐색 속도가 중요하면?
-
해쉬 컨테이너, 정렬된 vector 그리고 표준 연관 컨테이너의 순서대로 생각.

    반복자, 포인터, 참조자가 무효화 되는 일을 최소화 해야 하나?
-
노드 기반 컨테이너를 사용 : 노드 삽입과 삭제가 일어나도 기존의 반복자나 포인터 혹은 참조자가 무효화 되지 않음.
반면, 연속 메모리 컨테이너는 전체적인 메모리 재 할당이 빈번히 일어나기 때문에 반복자나 포인터, 참조자가 무효화 되기 쉽다.

    컨테이너 내의 데이터가 C의 데이터 타입과 메모리 배열 구조적으로  호환 되야 하면 vector!

Posted by 냉동
[ Programming ]2009. 4. 19. 01:24
프로그래밍을 하다보면 한번쯤은 다 써 봤을 것이다.

STL을 사용시 주의 할점이 있는데요.

begin()과 end()입니다.

begin()은 컨테이너의 첫번째 요소를 가르키고,
end()는 마지막의 유효한 요소 너머의 위치를 돌려 줍니다.

end()를 위와 같은 이유는

1. 빈 리스트에 대한 점검 코드를 생략 할수 있고,
2. 컨테이너의 요소를 차례로 탐색 하는 루프를 만들기가 쉽기 때문입니다.

물론 직관적이지 못한다는 단점도 있습니다.
마지막의 유효한 요소 너머의 위치를 돌려 주기 때문에 end() 위치를 가르키는 반복자를
역참조 해서는 안됩니다.

 STL 컨테이너들은 정보를 참조가 아니라, 
값의 의한 전달 이라서 포인터를 넘겨주는 것이 바람직합니다.
물론 적은 양의 데이터 같은 경우는 차이를 느끼지 못하겠지만, 
게임을 만들다 보면 큰 데이터를 넘기게 되면 그 차이는 말로 표현 못할 정도 입니다.

간단하게 STL의 주의 할점을 알아봤는데요...

Vector을 사용 할때 주의 할점은

push_front(), popfront()의 사용을 피하는것이 좋다는것입니다. 물론 안되는것은 아니지만, 
이처럼 데이터를 앞에 넣을 경우 그 전에 넣었던 데이터를 
전부 한칸씩 뒤로 미루어야 하기 때문에 부담이 되서 입니다.

'[ Programming ]' 카테고리의 다른 글

explicit  (0) 2009.04.30
팀 스위니 강연  (0) 2009.04.22
VAssistX.RefactorCreateImplementation  (0) 2009.04.21
Tab키 Space바 처럼 사용하기  (0) 2009.04.19
프로젝트 생성시 확장자  (0) 2009.04.19
Posted by 냉동