항목 17 : new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자
처리 우선순위를 알려 주는 함수가 하나 있고, 동적으로 할당한 Widget 객체에 대해 어떤 우선순위에 따라 처리를 적용하는 함수가 하나 있다고 가정합시다.
1
2
|
int prioirty();
void processWidget(std::tr1::shared_ptr<Widget> pw, int prioirty);
|
자원 관리에는 객체를 사용하는 것이 좋기 때문에 processWidget 함수는 동적 할당된 Widget 객체에 대해 스마트 포인터를 사용하도록 만들어졌습니다.
이렇게 만들어진 processWidget 함수를 이제 호출합니다.
1
|
processWidget(new Widget, prioirty());
|
이렇게 호출을 하면 컴파일이 되지 않습니다.
포인터를 받는 tr1::shared_ptr의 생성자는 explicit로 선언되어 있기 때문에, 'new Widget' 표현식에 의해 만들어진 포인터가 tr1::shared_ptr 타입의 객체로 바꾸는 암시적인 변환이 있을 리가 없기 때문입니다.
단, 아래의 코드는 컴파일 됩니다.
1
|
processWidget(std::tr1::shared_ptr<Widget>(new Widget), prioirty());
|
하지만 이 문장은 자원을 흘릴 가능성이 있습니다.
컴파일러는 processWidget 호출 코드를 만들기 전에 우선 이 함수의 매개변수로 넘겨지는 인자를 평가하는 순서를 밟습니다. 여기서 두 번째 인자는 prioriy 함수의 호출문밖에 없지만, 첫 번째 인자는 두 부분으로 나누어져 있습니다.
1. "new Widget" 표현식을 실행하는 부분
2. tr1::shared_ptr 생성자를 호출하는 부분
사정이 이렇기 때문에, processWidget 함수 호출이 이루어지기 전에 컴파일러는 다음의 세 가지 연산을 위한 코드를 만들어야 합니다.
- priority를 호출합니다.
- "new Widget"을 실행합니다.
- tr1::shared_ptr 생성자를 호출합니다.
그런데, 여기서 각각의 연산이 실행되는 순서는 컴파일러 제작사마다 다르다는 게 문제입니다.
예를 들어, 연산 순서가
1. "new Widget"을 실행합니다.
2. priority를 호출합니다.
3. tr1::shared_ptr 생성자를 호출합니다.
이렇게 정해졌다고 가정할 때 2번에서 예외가 발생한다면 "new Widget"으로 만들어졌던 포인터가 유실될 수 있습니다. 자원 누출을 막아 줄 줄 알고 준비한 tr1::shared_ptr에 저장되기도 전에 예외가 발생했으니까요.
결론을 말하자면, 자원이 누출될 가능성이 있는 이유는 자원이 생성되는 시점과 그 자원이 자원 관리 객체로 넘어가는 시점 사이에 예외가 끼어들 수 있기 때문입니다.
이런 문제를 피해 가는 방법은 간단합니다. Widget을 생성해서 스마트 포인터에 저장하는 코드를 별도의 문장 하나로 만들고, 그 스마트 포인터를 processWidget에 넘기는 것입니다.
1
2
3
|
std::tr1::shared_ptr<Widget> pw(new Widget); // new로 생성한 객체를 슴트 포인터에 담는 코드를 하나의 독립적인 문장으로 만듭니다.
processWidget(pw, prioirty()); // 이제는 자원 누출 걱정이 없습니다.
Colored by Color Scripter
|
꼭 잊지 말아야 할 것!
new로 생성한 객체를 스마트 포인터로 넣는 코드는 별도의 한 문장으로 만듭시다. 이것이 안 되어 있으면, 예외가 발생될 때 디버깅하기 힘든 자원 누출이 초래될 수 있습니다.
'언어 > C++' 카테고리의 다른 글
[Effective C++] 클래스 설계는 타입 설계와 똑같이 취급하자 (0) | 2020.01.19 |
---|---|
[Effective C++] 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 (0) | 2020.01.18 |
[Effective C++] new 및 delete를 사용할 때는 형태를 반드시 맞추자 (0) | 2020.01.16 |
[Effective C++] 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 (0) | 2020.01.15 |
[Effective C++] 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자 (0) | 2020.01.14 |