1. 매개변수로 스마트 포인터를 받는 경우
void processWidget(std::shared_ptr<Widget> pw, int priority);
int priority();
...
processWidget(new Widget(),priority()); // 컴파일 에러!
스마트 포인터의 생성자는 explicit로 선언되어 있기 때문에, 'new Widget()' 표현식에 의해 만들어진 포인터가 shared_ptr 타입의 객체로 바꾸는 암시적인 반환이 이루어질 수 없다. 반면에 아래의 코드는 동작 가능하다.
processWidget(std::shared_ptr<Widget>(new Widget(),priority());
하지만 위의 코드는 자원을 흘릴 가능성이 존재한다. 자원이 누출될 가능성이 있는 이유는, 자원이 생성되는 시점("new Widget"을 통한)과 그 자원이 자원 관리 객체로 넘어가는 시점 사이에 예외가 끼어들 수 있기 때문이다. 위의 코드는 다음과 같은 코드들을 만들어야 한다.
- priority()를 호출한다
- "new Widget"을 실행한다
- shared_ptr 생성자를 호출한다
그런데 c++ 컴파일러의 경우 위의 연산이 실행 되는 순서가 제각각이다. 따라서, 만약 다음과 같이 실행 순서가 정해진다면
- "new Widget"을 실행한다
- priority()를 호출한다
- shared_ptr 생성자를 호출한다
priority()를 호출하는 순간 예외를 던지는 경우 new 메모리 할당된 Widget 객체가 스마트 포인터에 넘겨지지 않았기에 메모리 누수가 일어나게 되는 것이다.
해결방법으로 스마트 포인터를 매개변수로 넘길수 있다.
std::shared_ptr<Widget> pw(new Widget());
processWidget(pw,priority());
이것만은 잊지 말자!
- new로 생성한 객체를 스마트 포인터로 넣는 코드는 별도의 한 문장으로 만듭시다. 이것이 안 되어 있으면, 예외가 발생될 때 디버깅하기 힘든 자원 누출이 초래될 수 있습니다.
'C++ > Effective C++' 카테고리의 다른 글
[Effective C++] 19. 클래스 설계는 타입 설계와 똑같이 취급하자. (0) | 2020.08.06 |
---|---|
[Effective C++] 18. 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 (0) | 2020.08.06 |
[Effective C++] 16. new 및 delete를 사용할 때는 형태를 반드시 맞추자 (0) | 2020.08.03 |
[Effective C++] 15. 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 (0) | 2020.08.03 |
[Effective C++] 14. 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자 (0) | 2020.08.03 |