처리 우선순위를 알려 주는 함수가 하나 있고, 동적으로 할당된 Widget 객체(자원)에 대해 어떤 우선순위에 따라 처리를 적용하는 함수가 하나 있다고 가정해보자.
자원 관리에는 자원 관리 객체를 사용하는 것이 좋다 => Widget 객체에 대해 스마트 포인터를 사용하도록 만들었다.
이렇게 만들어진 processWidget을 호출해보자.
tr1::shared_ptr의 생성자는 explicit으로 되어있기 때문에, 암시적 형 변환이 일어나지 않는다. 그래서 명시적 변환을 해줘야 한다.
이제 컴파일은 잘 되지만, 이 문장은 자원을 흘릴 가능성이 있다.(아니 자원 관리 객체를 쓰는데도 왜 자원이 샘?)
일단 첫번째 인자는 크게 두 개로 나눠어져 있음
- "new Widget" 표현식을 쓰는 부분
- tr1::shared_ptr 생성자를 호출하는 부분
이렇기 때문에 컴파일러는 processWidget()이 호출되기 전에 세 가지 연산을 위한 코드를 만들어야 한다.
- priority() 호출
- "new Widget" 실행
- tr1::shared_ptr 생성자 호출
=> 근데 여기서 컴파일러 제작사 마다 이 연산들이 실행되는 순서가 다를 수 있다!!(C++만의 특징, C#, JAVA 등은 매개변수의 평가 순서가 정해져 있다.)
일단 new Widget은 무조건 tr1::shared_ptr 생성자 보다 빨리 실행 되어야 한다. 당연히 new Widget의 리턴 포인터를 생성자의 인자로 넣는 것이기 때문이다. 하지만 priority()는 이 사이에 언제든 호출될 수 있다.
즉 이런 순서도 가능.
- "new Widget" 실행
- priority() 호출
- tr1::shared_ptr 생성자 호
이 때 priority()에서 예외가 발생하면? => new Widget에서 생성된 포인터가 유실될 것이다. => 자원 누출을 막아주는 자원 관리 객체에 들어가기도 전에 예외가 발생했기 때문이다. 그래서 이 순서를 명확히 하기 위해 다음과 같이 해주자.
- new로 생성한 객체를 스마트 포인터에 넣는 코드는 별도의 한 문장으로 만들자. 이것이 안 되어 있으면, 예외가 발생될 때 디버깅하기 힘든 자원 누출이 초래될 수 있다.
'Effective C++ > 3. 자원 관리' 카테고리의 다른 글
항목 16: new 및 delete를 사용할 때는 형태를 반드시 맞추자. (0) | 2021.04.24 |
---|---|
항목 15: 자원 관리 클래스에서 관리하는 자원은 외부에서 접근할 수 있도록 하자 (0) | 2021.04.24 |
항목 13: 자원 관리에는 객체가 그만! (0) | 2021.04.24 |