Widget이라는 클래스가 있고 우선순위를 반환하는 priority() 라는 함수와 shared_ptr객체와 우선순위를 매개변수로 받는 processWidget()함수가 있다고 하자(아래 코드를 보자)
class Widget
{
public:
};
int priority(){return 1;};
void processWidget(shared_ptr<Widget> pw,int priority)
{
cout<<"Call Func -> processWidget"<<endl;
}
int _tmain(int argc, char** argv) {
processWidget((new Widget),priority()); //error!
return 0;
}
위의 코드를 보면 processWidget변수에 (new Widget)으로 값을 넘기려 하고 있다. 하지만 이것은 불가능하다.
이유는 shared_ptr의 생성자는 explicit로 선언되어 묵시적으로 Widget으로 형변환이 되지 않기 때문이다.
대신 다음처럼은 쓸 수 있다.
int _tmain()
{
processWidget(shared_ptr<Widget>(new Widget), priority());
}
값을 넘길 때 아얘 shared_ptr<Widget>로 넘겨주는 거다.
그러면 "보통"의 컴파일러는 다음과 같이 연산순서를 정한다.
1. priority() 함수 호출 후 반환
2. new Widget 표현식 실행
3. shared_ptr 생성자 호출
모든 컴파일러가 이런 순서로 된다면 아무런 문제가 없을 것이다.
하지만 c++컴파일러의 경우에는 제작사 마다 순서가 다를정도로 순서에 대해 상당한 자유도가 있기때문에 다음과 같이 순서가 바뀌어 실행될 수도있다.
1. new Widget 표현식 실행
2. priority()를 호출 후 반환
3. shared_ptr 생성자 호출
만약 이 순서로 연산이 되었을 때 2번에서 예외가 발생하면 1번에서 할당한 Widget이라는 자원이 누출될것이다. 그러기 때문에 이 문제를 해결하는 방법은 Widget을 할당하고 shared_ptr에 넣는 문장과 processWidget함수에 스마트포인터를 넘기는 문장을 따로 나눠놓으면 된다.
다음 예제 코드를 보자
int _tmain()
{
shared_ptr<Widget>pw(new Widget); //new로 생성한 객체를
//스마트 포인터에 담는 코드를
//하나의 독립적인 문장으로 만든다.
processWidget(pw, priority()); //이제는 자원 누출 걱정이없다.
}
이것만은 잊지 말자!
1. new로 생성한 객체를 스마트 포인터로 넣는 코드는 별도의 한 문장으로 만듭시다. 이것이 안 되어 있으면, 예외가 발생될 때 디버깅하기 힘든 자원 누출이 초래될 수 있다.