일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 스마트 포인터
- 상속
- 예외
- UE4
- 루아
- 영화 리뷰
- 비교 함수 객체
- resource management class
- 반복자
- 참조자
- 언리얼
- implicit conversion
- 암시적 변환
- effective stl
- 메타테이블
- c++
- 다형성
- 티스토리챌린지
- Effective c++
- 영화
- operator new
- more effective c++
- reference
- exception
- lua
- Smart Pointer
- 게임
- virtual function
- 오블완
- Vector
Archives
- Today
- Total
스토리텔링 개발자
[Effective STL] 7. 컨테이너 요소 new, delete 짝 맞춤 문제 본문
728x90
항목 7. new로 생성한 포인터의 컨테이너를 사용할 때에는 컨테이너가 소멸되기 전에 포인터를 delete하는 일을 잊지 말자
컨테이너의 메모리 해제
- 보통의 경우 컨테이너는 요소의 메모리 해제를 잘 해 주지만..
- new로 할당된 객체 포인터의 경우 이야기가 다르다.
void doSomething()
{
vector<Widget*> vwp;
for(int i = 0 ; i < SOME_MAGIC_NUMBER ; ++i)
vwp.push_back(new Widget());
...
} // 메모리 누수 발생!
- vwp의 각 요소, 포인터 자체는 소멸되지만, 포인터가 가리키는 공간은 전혀 해제되지 않는다.
- 즉, 아래와 같이 해주어야 한다.
void doSomething()
{
vector<Widget*> vwp;
... // 예전과 동일
// 해제 처리를 해주어야 한다.
for(vector<WIdget*>::iterator i = vwp.begin(); i != vwp.end() ; ++i)
delete *i;
}
- 두 가지 문제
- STL적으로 보면 for보다는 for_each가 더 명확하다. (항목 43 참조)
- 예외 안전성(exception safety)을 갖추지 못했다.
- 메모리 해제 전 예외가 발생하면 여전히 누수가 발생한다.
for 루프를 for_each로 만들기
- delete를 수행하는 부분을 함수 객체(혹은 함수)로 바꾼다.
template<typename T>
struct DeleteObject : public unary_function<const T*, void>
{
void operator()(const T* ptr) const
{
delete ptr;
}
};
void doSomething()
{
...
for_each(vwp.begin(), vwp.end(), DeleteObject<Widget>());
}
- 하지만, T를 사용자가 직접 지정해주어야 하는 부분이 불만이다.
- 아래처럼 실수할 여지가 있다.
// string은 가상 소멸자가 없으므로
// 옳지 않은 상속이지만.. 일단 넘어가자.
class SpecialString : public string {...};
void doSomething()
{
deque<SpecialString*> dssp;
...
// SpecialString 타입을 삭제해야 하건만,
// string 타입을 삭제하도록 지정했다!
for_each(dssp.begin(), dssp.end(), DeleteObject<string>());
}
- 타입을 지정하지 않는 버전
struct DeleteObject
{
template<typename T>
void operator()(const T* ptr) const
{
delete ptr;
}
};
void doSomething()
{
deque<SpecialString*> dssp;
...
// 타입 지정이 필요하지 않다.
for_each(dssp.begin(), dssp.end(), DeleteObject());
}
- 모던 C++에 와서는 두 가지 방법이 더 있다.
- for_each와 람다를 사용
void doSomething()
{
deque<SpecialString*> dssp;
...
// 람다를 사용
for_each(dssp.begin(), dssp.end(), [](const T* ptr){
delete ptr;
});
}
- 범위 지정 for를 사용
void doSomething()
{
deque<SpecialString*> dssp;
...
// 범위 지정 for를 사용
for(auto ptr : dssp)
{
delete ptr;
}
}
예외 안전성 챙기기
- 가장 간단한 방법은 스마트 포인터를 사용하는 방법이다.(More Effective C++ 항목 28)
void doSomething()
{
vector< std::shared_ptr<Widget> > vwp;
for(int i = 0 ; i < SOME_MAGIC_NUMBER ; ++i)
vwp.push_back(std::shared_ptr<Widget>(new Widget));
...
}
추가 정리
- 컨테이너의 요소로 auto_ptr을 사용하는 것은 금물이다. (항목 8 참조)
- DeleteArray 구조체를 만들어서 배열의 포인터를 요소로 하는 컨테이너를 처리할 수 있지 않을까?
- 가능은 하지만...
- 동적 할당된 배열은 vector나 string 객체보다 나쁘다.(항목 13 참조)
728x90
'개발 > Effective STL' 카테고리의 다른 글
[Effective STL] 9. 컨테이너별 요소 삭제 (0) | 2024.11.13 |
---|---|
[Effective STL] 8. auto_ptr 금지 (0) | 2024.11.12 |
[Effective STL] 6. 컴파일러의 분석 오류 (0) | 2024.11.08 |
[Effective STL] 5. 범위 멤버 함수(Range Member Function) (0) | 2024.11.07 |
[Effective STL] 4. 빈 컨테이너인지 확인하기 (0) | 2024.11.04 |
Comments