KoreanFoodie's Study
Effective C++ | 항목 17 : new 로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자 본문
Tutorials/C++ : Advanced
Effective C++ | 항목 17 : new 로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자
GoldGiver 2022. 10. 25. 16:11
C++ 프로그래머의 필독서이자 바이블인, 스콧 마이어스의 Modern Effective C++ 를 읽고 기억할 내용을 요약하고 있습니다. 꼭 읽어보시길 추천드립니다!
항목 17 : new 로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자
핵심 :
new 로 생상한 객체를 스마트 포인터로 넣는 코드는 별도의 한 문장으로 만들자. 이것이 안 되어 있으면, 예외가 발생될 때 디버깅하기 힘든 자원 누출이 초래될 수 있다!
처리 우선순위를 알려주는 함수가 하나 있고, 동적으로 할당한 Widget 객체에 대해 어떤 우선순위에 따라 처리를 적용하는 함수가 하나 있다고 가정하자.
int priority();
void processWidget(std::shared_ptr<Widget> pw, int priority)
...
// 함수를 호출해보자
processWidget(new Widget, priority());
하지만 위의 코드는 컴파일이 되지 않는다. 왜일까?
포인터를 받는 shared_ptr 의 생성자는 explicit 으로 선언되어 있기 때문에, 'new Widget' 표현식에 의해 만들어진 포인터가 shared_ptr 타입의 객체로 바뀌는 암시적인 변환이 일어날 수 없기 때문이다! 따라서 다음 코드는 컴파일이 된다.
processWidget(std::shared_ptr<Widget>(new Widget), priority());
하지만 위 문장은 매우 위험한 점이 숨겨져 있다.
먼저, shared_ptr 는 다음과 같은 부분으로 나뉘어 있다.
- 'new Widget' 표현식을 실행하는 부분
- shared_ptr 생성자를 호출하는 부분
그런데, processWidget 에는 priority( ) 함수가 호출되는 부분이 있는데, 다음과 같이 순서가 섞인다고 가정해 보자(인자를 처리하는 순서는 컴파일러마다 다르다).
- 'new Widget' 표현식을 실행하는 부분
- priority 호출
- shared_ptr 생성자를 호출하는 부분
만약 priority 를 호출하는 과정에서 예외가 발생한다면, "new Widget" 으로 만들어졌던 포인터가 유실될 수 있다! 즉, 자원이 생성되는 시점(1번) 과 자원이 자원 관리 객체로 넘어가는 시점(3번) 사이에 예외가 끼어들 수 있다는 것이다!
이 문제를 피하기 위해서는, Widget 을 생성해서 스마트 포인터에 저장하는 코드를 별도의 문장으로 만들고, 그 스마트 포인터를 processWidget 에 넘기기만하면 된다!
// 독립적인 문장으로 만들기
std::shared_ptr<Widget> pw(new Widget);
// 이제 자원 누출 걱정이 없다!
processWidget(pw, priority());
이제 컴파일러의 눈치를 보지 않는, 안전한 코드가 만들어졌다!
'Tutorials > C++ : Advanced' 카테고리의 다른 글
Effective C++ | 항목 19 : 클래스 설계는 타입 설계와 똑같이 취급하자 (0) | 2022.10.25 |
---|---|
Effective C++ | 항목 18 : 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 (0) | 2022.10.25 |
Effective C++ | 항목 16 : new 및 delete 를 사용할 때는 형태를 반드시 맞추자 (0) | 2022.10.25 |
Effective C++ | 항목 15 : 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 (0) | 2022.10.25 |
Effective C++ | 항목 14 : 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자 (0) | 2022.10.25 |
Comments