EFFECTIVE C++ 정리
Chapter 3
자원관리는 전문가에게
ITEM 13
Item 13: 자원관리는 전문가에게
• 자원이란?
• 시스템한테 받아오는 빚(?) 같은것…
• 사용할 때 할당 받고 사용을 다하면 해제하는 것
• 메모리, 뮤텍스, 파일 등등…
• New / Delete , Get / Release
• 확실하게 하지 않으면 자원 낭비(누수)
• 버릇을 들이는 것이 중요
• 혹은 전문가(클래스)에게 맡겨 주자!!! (이번 장의 요지)
Item 13: 자원관리는 전문가에게
• 투자 모델링 클래스를 만들어 보자
• class Investment { …. };
• 팩토리 함수를 통해서 객체를 받아온다.
• Investment* createInvestment();
• 그렇다면 해제는 받아온 사람이 해야겠지?
• Investment* pInv = createInvestment();
… //do Something
delete pInvestment;
Item 13: 자원관리는 전문가에게
• 과연 제대로 동작할까?
• 제대로 해제하려면 반드시 delete가 호출
• ‘…’ 부분에서 중도 하차한다면?
• 중간에 return
• 중간에 throw
• 중간에 loop break;
• 해제가 제대로 되지 않을 엄청난 가능성!!
Item 13: 자원관리는 전문가에게
• 자원 관리하는 객체를 사용하자!
• 자원을 객체에 넣고 해제는 소멸자에
• 어떤 식이든 Scope를 벗어나면 클래스는 소멸자를 호출하게된다.
• void ResourceExample() {
ResourceManger rm; //생성
…
} //어떤 식이든 scope를 떠나면 소멸자가 호출된다.
Item 13: 자원관리는 전문가에게
• auto_ptr을 써보자 (c++98 기준)
• 포인터와 비슷하게 동작하는 자원 관리 클래스(smart pointer)
• 가리키는 대상에 대해서 소멸자가 delet를 호출하는 방식
• void ResourceExample(){
std::auto_ptr<Investment> pInv( createInvestment() );
….
} //소멸자 호출 == delete
Item 13: 자원관리는 전문가에게
• 예제 설명
• 자원을 할당한 뒤 곧.바.로 자원관리 객체에게 넘겨주자 (RAII)
• createInvestment로 자원을 만들고 auto_ptr의 생성자로 넘겨준다.
• 자원 획득 == 초기화 (Resource Acquisition is Initialization : RAII)
• 쓸데없이 다른 곳에 자원의 포인터가 넘어가는 것을 방지
• 하나의 자원은 하나의 자원 관리자에게만!
• 소멸자 해제로 확실한 해제를 보장한다.
• return/break/throw 뭐가되었건 scope가 벗어나면 소멸자가 호출된다.
Item 13: 자원관리는 전문가에게
• 관리 객체의 복사는 허용하지 않는다.
• auto_ptr에서 복사 생성자 또는 대입연산자를 호출하는 경우
• 대상 객체에 정보를 넘기고 원본은 NULL로 변한다.
• 하나의 자원에는 하나의 자원관리자만!
• 복사가 허용되지 않으면 일반적인 포인터랑은 조금 다른데요?
• 우리는 여기저기서 할당된 자원을 공유할 필요가 있다.
• Scope가 넘어가도 살아있었으면 좋겠어
• 그래서 좀더 기능이 많은 관리자들이 필요함!
Item 13: 자원관리는 전문가에게
• 참조 카운팅 방식 스마트 포인터 (RCSP)
• 자원이 외부에서 몇번이나 사용되고 있는지를 체크
• 새로 받아서 쓰면 ++, 다 썼으면 –
• 0이 되면 해제 (delete)
• Java의 garbage collectio의 동작방식 (개략적이지만)
Item 13: 자원관리는 전문가에게
• tr1::shared_ptr (c++11 std::shared_ptr)
• Item 54에서 자세히 다룰예정이니 여기서는 너무 기대말자
• Garbage Collection이랑 달리 순환참조는 알아서 체크해야됨
• void ResourceExample(){
std::tr1::shared_ptr<Investment>
pInv( createInvestment() ); //참조 카운트 ++ (1)
} //참조 카운트 -- (0) 해제
Item 13: 자원관리는 전문가에게
• void ResourceExample(){
std::tr1::shared_ptr<Investment>
pInv( createInvestment() ); //참조 카운트 ++ (1)
…
Other -> GetSP( pInv ); //다른 객체에게 전달
//카운트 ++ (2)
} //참조 카운트 – (1) 삭제 안되고 다른 객체가 쓸수있다.
Item 13: 자원관리는 전문가에게
• 배열 자원은 auto_ptr / share_ptr 쓰지말자
• auto/share_ptr 소멸자에서 단순 delete만 수행 (c++ 98)
• 그러니까 delete [] 안된다
• 배열의 자원관리는 auto_ptr / shared_ptr 사용하면안된다.
• std::vector / std::string 등의 컨테이너 클래스를 사용하자.
자원관리자 복사는 신중히
ITEM 14
Item 14 : 자원관리자 복사는 신중히
• 메모리 자원만 auto/share_ptr 가능하다.
• auto/shared_ptr은 소멸자에서 delete만 수행(c++ 98)
• 다른 자원 (뮤텍스, 파일, DB…etc)은 어떻게 관리하지?
• 룰은 이해했으니 직접 만들자.
• 뮤텍스라면 잠금/해제 == 자원획득/자원해제
• void lock(Mutex* pm);
• void unlock(Mutex* pm);
Item 14 : 자원관리자 복사는 신중히
• class Lock {
public:
explicit Lock( Mutex* pm ) : mutexPtr( pm )
{ lock( mutexPtr ); } //생성자에서 자원 획득
~Lock() { unlock ( mutexPtr ); } //소멸자에서 자원 해제
private:
Mutex* mutexPtr;
}
Item 14 : 자원관리자 복사는 신중히
• void LockExample(){
Mutex m;
…
{
Lock ml( &m ); // Lock 생성자 호출 : 자원 획득
…
} // Lock 소멸자 호출 : 자원 해제
}
Item 14 : 자원관리자 복사는 신중히
• 문제는 Lock 자원 객체의 복사 (이번 아이템 주제)
• 복사 생성자, 대입연산자를 어떻게 구성할 것인가!
• 뮤텍스를 복사하면 발생할 수 있는 수많은 문제들
• 서로 다른 Lock이 서로서로에게 영향을 받음
• 원하지 않은 타이밍에 락 해제가 된다면…
• 서로 다른 자원 관리자가 자원을 공유해선 안됨!
Item 14 : 자원관리자 복사는 신중히
• 복사 동작을 어떻게 할 것인가
1. 복사를 금지한다
• 사본이 존재하면 안되는 경우 : ex) Mutex
• Item 6에서 봉인술을 설명했으니 참조
2. 관리 자원의 참조 카운팅을 수행한다.
• 사용자가 있는한 유지되어야 하는 자원인 경우
• 관리 자원의 포인터를 shared_ptr<T>로 변경하면 쉽게 구현가능
• Shared_ptr에서 제공하는 deleter지정(소멸자에서 호출할 함수지정)을 활용하자.
Item 14 : 자원관리자 복사는 신중히
• class Lock {
public:
explicit Lock( Mutex* pm )
: mutexPtr( pm , unlock ) //deleter로 unlock등록
{ lock( mutexPtr.get() ); } //생성자에서 자원 획득
private:
std::tr1::shared_ptr<Mutex> mutexPtr; //shared_ptr
}
Item 14 : 자원관리자 복사는 신중히
• share_ptr로 관리한다면 소멸자가 필요없다.
• 참조 카운터가 0 이되면 관리 자원의 deleter를 호출하니까!
• Deleter로 unlock을 지정했다.
• 참조 카운터가 0이되면 unlock이 호출된다.
Item 14 : 자원관리자 복사는 신중히
3. 관리 자원을 그냥 복사한다
• 자원 관리 객체를 복사할 때는 깊은 복사를 수행하자.
• 새로 자원을 할당 받은 뒤에 복사할 것
• string 을 복사한다고 가정
• 단순히 주소만 복사한다면 같은 자원을 서로 다른 관리자가 물고있는 것
• 입 아프게 설명한 여러 문제들 발생 (두 번 해제, 댕글링 포인터 등등)
• 메모리를 따로 할당한 뒤 내용을 복사하자.
Item 14 : 자원관리자 복사는 신중히
4. 자원의 소유권을 이전한다.
• 자원을 참조하는 객체가 딱 하나만 존재해야할 때
• auto_ptr의 복사와 동일하게
• 기존 객체를 지우고 새객체에 옮긴다.
• C++11 unique_ptr 훌륭하게 잘 만듦
관리자원은 접근 가능하게
ITEM 15
Item 15 : 관리자원은 접근 가능하게
• 많은 API들은 자원에 직접 접근하기를 원한다.
• Int daysHeld ( const Investment* pi );
• tr1::std::shared_ptr<Investment> pInv;를 사용해보자.
• int day = daysHeld( pInv ); // 에러
• 함수가 원하는 건 자원의 포인터!
• 직접 자원에 접근할 수 있는 get함수를 활용한다.
• Int day = daysHeld( pInv.get() ); // 잘 동작한다.
Item 15 : 관리자원은 접근 가능하게
• 역참조 연산자도 오버로딩되어있다.
bool Investment::IsTexFree(); //Investment클래스 멤버 함수
…
std::tr1::shared_ptr<Investment> pi1( createInvestment() );
bool texable1 = !(pi1->IsTaxFree() ); //operator ->
bool texable2 = !((*pi1).IsTaxFree() ); //operator *
Item 15 : 관리자원은 접근 가능하게
• 자원관리자  자원 : 암시적 형변환의 지원
• 명시적으로 getter를 쓰는게 좋긴 한데 귀찮은 경우.
• 암시적 변환 함수를 제공하면 된다.
Class Font{
public:
operator FontHandler() const { return f;}
private:
FontHandler f;
}
Item 15 : 관리자원은 접근 가능하게
• 암시적 형변환은 실수의 여지가 많기 때문에 조심하자
void FontExample(FontHandler fh);
…
Font font1;
FontExample(font1); //어이없는 형 변환 ,
//댕글링 포인터 문제 야기
new delete 형식 맞추자
ITEM 16
Item 16 : new delete 형식 맞추자
• New 동작 구조
• 메모리 할당 (operator new)
• 할당된 메모리에 대해 한 개 이상의 생성자가 호출된다.
• Delete 동작 구조
• 대상 메모리에 대한 소멸자가 호출
• 메모리 해제 (operator delete)
Item 16 : new delete 형식 맞추자
• 단일 객체 vs 배열
• 메모리 구조가 다르다.
• 배열의 크기 정보가 들어감
Item 16 : new delete 형식 맞추자
• 배열 Delete를 적용할 때 []를 써주자.
• []는 이제 삭제하려는 것이 배열임을 명시하는 것.
• 첫 번째 정보인 n 을 읽어서 배열 전체를 삭제한다.
• 단일 객체 Delete에 []를 쓴다면?
• 첫 번째 정보 n을 읽으려고 한다….
• 이상한 값을 읽어서 마구 지워버리겠지…
Item 16 : new delete 형식 맞추자
• 간단한 규칙
• New에 []를 썼으면 (배열 생성이면)
• Delete에도 []를 써라… (제발)
• 반대도 마찬가지!
• 생성자에서 new / 소멸자에서 delete
• 다른 곳에서 하면 햇갈려서 실수하기 쉽다.
Item 16 : new delete 형식 맞추자
• typedef 를 사용한다면 배열인지 아닌지 명시해라
typedef std::string AddressLines[4]; //AddressLines는 string 배열타입
std::string* pal = new AddressLines; //배열 생성자임을 잊지말자.
…
delete pal; //햇갈려서 이렇게 쓰면 큰일
delete [] pal; //이렇게 써야된다.
• 가능하면 배열은 typedef 하지말자…(제발)
• std::vector 쓰면 간단하게 해결될 일
자원 저장은 RAII합시다
ITEM 17
Item 17 : 자원 저장은 RAII합시다
• 예제
• Widget 객체에 우선순위에 따라 처리하는 함수
• void ProcessWidget(std::tr1::shared_ptr<Widget> pw, int priority);
• 우선순위 리턴 함수
• Int Priority();
• 사용
• ProcessWidget( new Wiget(), priority ); //에러
Item 17 : 자원 저장은 RAII합시다
• shared_ptr의 생성자는 explicit로 선언되어있음
• Widget*  shared_ptr<Widget> 암묵적 형변환 안 된다.
• 그래서
• ProcessWidget(std::tr1::shared_ptr<Widget>(new Widget), Priority());
• 하지만
• 자원 누수의 가능성!
Item 17 : 자원 저장은 RAII합시다
• 왜때문인가?
• ProcessWidget(std::tr1::shared_ptr<Widget>(new Widget),Priority())
• 우리가 기대하는 동작 순서
• new Widget 실행  tr1::shared_ptr 생성자 호출  Priority 계산
• 하지만 이 셋의 연산 순서가 컴파일러마다 다르다!
• 최악의 경우
• New Widget  Priority 호출  tr1::std::shared_ptr 생성자 호출
• Priority에서 오류 발생하면? 메모리 누수!
Item 17 : 자원 저장은 RAII합시다
• 문제점
• 자원 할당 시점과 자원 관리 객체로 넘어가는 시점 사이
• 다른 작업이 끼어들어 예외를 발생시켰기 때문
• RAII하자고! (Resource Allocation is Initailization)
• 해결책
• Std::tr1::shared_ptr<Widget> pw( new Widget ); //자원 저장 별도
ProcessWidget( pw, Priority() ); // No leak, No stresss

Effective C++ 정리 chapter 3

  • 1.
  • 2.
  • 3.
    Item 13: 자원관리는전문가에게 • 자원이란? • 시스템한테 받아오는 빚(?) 같은것… • 사용할 때 할당 받고 사용을 다하면 해제하는 것 • 메모리, 뮤텍스, 파일 등등… • New / Delete , Get / Release • 확실하게 하지 않으면 자원 낭비(누수) • 버릇을 들이는 것이 중요 • 혹은 전문가(클래스)에게 맡겨 주자!!! (이번 장의 요지)
  • 4.
    Item 13: 자원관리는전문가에게 • 투자 모델링 클래스를 만들어 보자 • class Investment { …. }; • 팩토리 함수를 통해서 객체를 받아온다. • Investment* createInvestment(); • 그렇다면 해제는 받아온 사람이 해야겠지? • Investment* pInv = createInvestment(); … //do Something delete pInvestment;
  • 5.
    Item 13: 자원관리는전문가에게 • 과연 제대로 동작할까? • 제대로 해제하려면 반드시 delete가 호출 • ‘…’ 부분에서 중도 하차한다면? • 중간에 return • 중간에 throw • 중간에 loop break; • 해제가 제대로 되지 않을 엄청난 가능성!!
  • 6.
    Item 13: 자원관리는전문가에게 • 자원 관리하는 객체를 사용하자! • 자원을 객체에 넣고 해제는 소멸자에 • 어떤 식이든 Scope를 벗어나면 클래스는 소멸자를 호출하게된다. • void ResourceExample() { ResourceManger rm; //생성 … } //어떤 식이든 scope를 떠나면 소멸자가 호출된다.
  • 7.
    Item 13: 자원관리는전문가에게 • auto_ptr을 써보자 (c++98 기준) • 포인터와 비슷하게 동작하는 자원 관리 클래스(smart pointer) • 가리키는 대상에 대해서 소멸자가 delet를 호출하는 방식 • void ResourceExample(){ std::auto_ptr<Investment> pInv( createInvestment() ); …. } //소멸자 호출 == delete
  • 8.
    Item 13: 자원관리는전문가에게 • 예제 설명 • 자원을 할당한 뒤 곧.바.로 자원관리 객체에게 넘겨주자 (RAII) • createInvestment로 자원을 만들고 auto_ptr의 생성자로 넘겨준다. • 자원 획득 == 초기화 (Resource Acquisition is Initialization : RAII) • 쓸데없이 다른 곳에 자원의 포인터가 넘어가는 것을 방지 • 하나의 자원은 하나의 자원 관리자에게만! • 소멸자 해제로 확실한 해제를 보장한다. • return/break/throw 뭐가되었건 scope가 벗어나면 소멸자가 호출된다.
  • 9.
    Item 13: 자원관리는전문가에게 • 관리 객체의 복사는 허용하지 않는다. • auto_ptr에서 복사 생성자 또는 대입연산자를 호출하는 경우 • 대상 객체에 정보를 넘기고 원본은 NULL로 변한다. • 하나의 자원에는 하나의 자원관리자만! • 복사가 허용되지 않으면 일반적인 포인터랑은 조금 다른데요? • 우리는 여기저기서 할당된 자원을 공유할 필요가 있다. • Scope가 넘어가도 살아있었으면 좋겠어 • 그래서 좀더 기능이 많은 관리자들이 필요함!
  • 10.
    Item 13: 자원관리는전문가에게 • 참조 카운팅 방식 스마트 포인터 (RCSP) • 자원이 외부에서 몇번이나 사용되고 있는지를 체크 • 새로 받아서 쓰면 ++, 다 썼으면 – • 0이 되면 해제 (delete) • Java의 garbage collectio의 동작방식 (개략적이지만)
  • 11.
    Item 13: 자원관리는전문가에게 • tr1::shared_ptr (c++11 std::shared_ptr) • Item 54에서 자세히 다룰예정이니 여기서는 너무 기대말자 • Garbage Collection이랑 달리 순환참조는 알아서 체크해야됨 • void ResourceExample(){ std::tr1::shared_ptr<Investment> pInv( createInvestment() ); //참조 카운트 ++ (1) } //참조 카운트 -- (0) 해제
  • 12.
    Item 13: 자원관리는전문가에게 • void ResourceExample(){ std::tr1::shared_ptr<Investment> pInv( createInvestment() ); //참조 카운트 ++ (1) … Other -> GetSP( pInv ); //다른 객체에게 전달 //카운트 ++ (2) } //참조 카운트 – (1) 삭제 안되고 다른 객체가 쓸수있다.
  • 13.
    Item 13: 자원관리는전문가에게 • 배열 자원은 auto_ptr / share_ptr 쓰지말자 • auto/share_ptr 소멸자에서 단순 delete만 수행 (c++ 98) • 그러니까 delete [] 안된다 • 배열의 자원관리는 auto_ptr / shared_ptr 사용하면안된다. • std::vector / std::string 등의 컨테이너 클래스를 사용하자.
  • 14.
  • 15.
    Item 14 :자원관리자 복사는 신중히 • 메모리 자원만 auto/share_ptr 가능하다. • auto/shared_ptr은 소멸자에서 delete만 수행(c++ 98) • 다른 자원 (뮤텍스, 파일, DB…etc)은 어떻게 관리하지? • 룰은 이해했으니 직접 만들자. • 뮤텍스라면 잠금/해제 == 자원획득/자원해제 • void lock(Mutex* pm); • void unlock(Mutex* pm);
  • 16.
    Item 14 :자원관리자 복사는 신중히 • class Lock { public: explicit Lock( Mutex* pm ) : mutexPtr( pm ) { lock( mutexPtr ); } //생성자에서 자원 획득 ~Lock() { unlock ( mutexPtr ); } //소멸자에서 자원 해제 private: Mutex* mutexPtr; }
  • 17.
    Item 14 :자원관리자 복사는 신중히 • void LockExample(){ Mutex m; … { Lock ml( &m ); // Lock 생성자 호출 : 자원 획득 … } // Lock 소멸자 호출 : 자원 해제 }
  • 18.
    Item 14 :자원관리자 복사는 신중히 • 문제는 Lock 자원 객체의 복사 (이번 아이템 주제) • 복사 생성자, 대입연산자를 어떻게 구성할 것인가! • 뮤텍스를 복사하면 발생할 수 있는 수많은 문제들 • 서로 다른 Lock이 서로서로에게 영향을 받음 • 원하지 않은 타이밍에 락 해제가 된다면… • 서로 다른 자원 관리자가 자원을 공유해선 안됨!
  • 19.
    Item 14 :자원관리자 복사는 신중히 • 복사 동작을 어떻게 할 것인가 1. 복사를 금지한다 • 사본이 존재하면 안되는 경우 : ex) Mutex • Item 6에서 봉인술을 설명했으니 참조 2. 관리 자원의 참조 카운팅을 수행한다. • 사용자가 있는한 유지되어야 하는 자원인 경우 • 관리 자원의 포인터를 shared_ptr<T>로 변경하면 쉽게 구현가능 • Shared_ptr에서 제공하는 deleter지정(소멸자에서 호출할 함수지정)을 활용하자.
  • 20.
    Item 14 :자원관리자 복사는 신중히 • class Lock { public: explicit Lock( Mutex* pm ) : mutexPtr( pm , unlock ) //deleter로 unlock등록 { lock( mutexPtr.get() ); } //생성자에서 자원 획득 private: std::tr1::shared_ptr<Mutex> mutexPtr; //shared_ptr }
  • 21.
    Item 14 :자원관리자 복사는 신중히 • share_ptr로 관리한다면 소멸자가 필요없다. • 참조 카운터가 0 이되면 관리 자원의 deleter를 호출하니까! • Deleter로 unlock을 지정했다. • 참조 카운터가 0이되면 unlock이 호출된다.
  • 22.
    Item 14 :자원관리자 복사는 신중히 3. 관리 자원을 그냥 복사한다 • 자원 관리 객체를 복사할 때는 깊은 복사를 수행하자. • 새로 자원을 할당 받은 뒤에 복사할 것 • string 을 복사한다고 가정 • 단순히 주소만 복사한다면 같은 자원을 서로 다른 관리자가 물고있는 것 • 입 아프게 설명한 여러 문제들 발생 (두 번 해제, 댕글링 포인터 등등) • 메모리를 따로 할당한 뒤 내용을 복사하자.
  • 23.
    Item 14 :자원관리자 복사는 신중히 4. 자원의 소유권을 이전한다. • 자원을 참조하는 객체가 딱 하나만 존재해야할 때 • auto_ptr의 복사와 동일하게 • 기존 객체를 지우고 새객체에 옮긴다. • C++11 unique_ptr 훌륭하게 잘 만듦
  • 24.
  • 25.
    Item 15 :관리자원은 접근 가능하게 • 많은 API들은 자원에 직접 접근하기를 원한다. • Int daysHeld ( const Investment* pi ); • tr1::std::shared_ptr<Investment> pInv;를 사용해보자. • int day = daysHeld( pInv ); // 에러 • 함수가 원하는 건 자원의 포인터! • 직접 자원에 접근할 수 있는 get함수를 활용한다. • Int day = daysHeld( pInv.get() ); // 잘 동작한다.
  • 26.
    Item 15 :관리자원은 접근 가능하게 • 역참조 연산자도 오버로딩되어있다. bool Investment::IsTexFree(); //Investment클래스 멤버 함수 … std::tr1::shared_ptr<Investment> pi1( createInvestment() ); bool texable1 = !(pi1->IsTaxFree() ); //operator -> bool texable2 = !((*pi1).IsTaxFree() ); //operator *
  • 27.
    Item 15 :관리자원은 접근 가능하게 • 자원관리자  자원 : 암시적 형변환의 지원 • 명시적으로 getter를 쓰는게 좋긴 한데 귀찮은 경우. • 암시적 변환 함수를 제공하면 된다. Class Font{ public: operator FontHandler() const { return f;} private: FontHandler f; }
  • 28.
    Item 15 :관리자원은 접근 가능하게 • 암시적 형변환은 실수의 여지가 많기 때문에 조심하자 void FontExample(FontHandler fh); … Font font1; FontExample(font1); //어이없는 형 변환 , //댕글링 포인터 문제 야기
  • 29.
    new delete 형식맞추자 ITEM 16
  • 30.
    Item 16 :new delete 형식 맞추자 • New 동작 구조 • 메모리 할당 (operator new) • 할당된 메모리에 대해 한 개 이상의 생성자가 호출된다. • Delete 동작 구조 • 대상 메모리에 대한 소멸자가 호출 • 메모리 해제 (operator delete)
  • 31.
    Item 16 :new delete 형식 맞추자 • 단일 객체 vs 배열 • 메모리 구조가 다르다. • 배열의 크기 정보가 들어감
  • 32.
    Item 16 :new delete 형식 맞추자 • 배열 Delete를 적용할 때 []를 써주자. • []는 이제 삭제하려는 것이 배열임을 명시하는 것. • 첫 번째 정보인 n 을 읽어서 배열 전체를 삭제한다. • 단일 객체 Delete에 []를 쓴다면? • 첫 번째 정보 n을 읽으려고 한다…. • 이상한 값을 읽어서 마구 지워버리겠지…
  • 33.
    Item 16 :new delete 형식 맞추자 • 간단한 규칙 • New에 []를 썼으면 (배열 생성이면) • Delete에도 []를 써라… (제발) • 반대도 마찬가지! • 생성자에서 new / 소멸자에서 delete • 다른 곳에서 하면 햇갈려서 실수하기 쉽다.
  • 34.
    Item 16 :new delete 형식 맞추자 • typedef 를 사용한다면 배열인지 아닌지 명시해라 typedef std::string AddressLines[4]; //AddressLines는 string 배열타입 std::string* pal = new AddressLines; //배열 생성자임을 잊지말자. … delete pal; //햇갈려서 이렇게 쓰면 큰일 delete [] pal; //이렇게 써야된다. • 가능하면 배열은 typedef 하지말자…(제발) • std::vector 쓰면 간단하게 해결될 일
  • 35.
  • 36.
    Item 17 :자원 저장은 RAII합시다 • 예제 • Widget 객체에 우선순위에 따라 처리하는 함수 • void ProcessWidget(std::tr1::shared_ptr<Widget> pw, int priority); • 우선순위 리턴 함수 • Int Priority(); • 사용 • ProcessWidget( new Wiget(), priority ); //에러
  • 37.
    Item 17 :자원 저장은 RAII합시다 • shared_ptr의 생성자는 explicit로 선언되어있음 • Widget*  shared_ptr<Widget> 암묵적 형변환 안 된다. • 그래서 • ProcessWidget(std::tr1::shared_ptr<Widget>(new Widget), Priority()); • 하지만 • 자원 누수의 가능성!
  • 38.
    Item 17 :자원 저장은 RAII합시다 • 왜때문인가? • ProcessWidget(std::tr1::shared_ptr<Widget>(new Widget),Priority()) • 우리가 기대하는 동작 순서 • new Widget 실행  tr1::shared_ptr 생성자 호출  Priority 계산 • 하지만 이 셋의 연산 순서가 컴파일러마다 다르다! • 최악의 경우 • New Widget  Priority 호출  tr1::std::shared_ptr 생성자 호출 • Priority에서 오류 발생하면? 메모리 누수!
  • 39.
    Item 17 :자원 저장은 RAII합시다 • 문제점 • 자원 할당 시점과 자원 관리 객체로 넘어가는 시점 사이 • 다른 작업이 끼어들어 예외를 발생시켰기 때문 • RAII하자고! (Resource Allocation is Initailization) • 해결책 • Std::tr1::shared_ptr<Widget> pw( new Widget ); //자원 저장 별도 ProcessWidget( pw, Priority() ); // No leak, No stresss