아래 코드를 보자
1 2 3 4 5 6 7 | int priority(); void processWidget( std::tr1::shared_ptr<Widget> pw, int priority ); ... processWidget(new Widget, priority()); //컴파일 에러 |
이 코드가 컴파일 에러가 나는 이유는 std::tr1::shared_ptr 의 생성자는 explicit 되어있기때문에 new Widget 같은 표현식이 올수 없다.
processWidget(std::tr1::shared_ptr<Widget>(new Widget), priority());
위의 코드는 컴파일에 문제가 없다.
하지만, 스마트 포인터로 받은 자원을 흘릴 가능성이 있는 함수다.
왜 그럴까?
C++함수는 함수를 호출할때 함수로 들어오는 인자의 평가 순서를 지니게 된다.
첫번째 인자는 (new Widget) 과 std::tr1::shared_ptr의 생성자 호출부분으로 나뉜다.
두번째 인자는 함수포인터로 함수의 호출문이 있다.
우선 위의 함수가 호출될때 컴파일러는 세가지 연산을 위한 코드를 만든다.
1. priority를 호출한다.
2. new widget 을 실행한다.
3. std::tr1::shared_ptr 생성자를 호출합니다.
이 연산이 실행되는 순서는 컴파일러 제작사마다 다르다.
우선 std::tr1::shared_ptr은 new widget 이 실행되야지만, 실행되는 순서이다. 그렇기 때문에 순서가 변하지는 않지만, priority는 처음 호출될수도 있고, 두번째, 세번째도 호출될 수도 있습니다.
이때 2번과 3번 중간에 priority 함수가 호출되서 예외가 발생했다면, 자원을 막아줄줄 알고 준비한 std::tr1::shared_ptr에 저장되기도 전에 예외가 발생합니다.
위와같은 문제를 해결하기 위해서는?
어찌되었든 가장중요한 건!!
ProcessWidget 함수가 호출되기전에 Widget을 생성해서 스마트 포인터에 저장하는 코드를 별도의 한문장으로 하나 만들고, 그 스마트포인터를 넘기는 것입니다.
std::tr1::shared_ptr<Widget> pw( new Widget );
processWidget( pw, priority() );
이것 만은 잊지 말자!
◆ new로 생성한 객체를 스마트 포인터로 넣는 코드는 별도의 한 문장으로 만듭시다. 이것이 안되어 있으면, 예외가 발생될 때 디버깅하기 힘든 자원 누출이 초래될 수 있습니다.
'0x0001 > Effective C++' 카테고리의 다른 글
[Effective C++] 항목 19 : 클래스 설계는 타입 설계와 똑같이 취급하자 (0) | 2019.02.13 |
---|---|
[Effective C++] 항목 18 : 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 (0) | 2019.02.13 |
[Effective C++] 항목 16 : new 및 delete를 사용할 때는 형태를 반드시 맞추자 (0) | 2019.02.13 |
[Effective C++] 항목 15 : 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 (0) | 2019.02.12 |
[Effective C++] 항목 14 : 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자 (0) | 2019.02.12 |