본문 바로가기

Effective C++/3. 자원 관리

항목 17: new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자.

처리 우선순위를 알려 주는 함수가 하나 있고, 동적으로 할당된 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() 사이에 언제든 호출될 있다.

이런 순서도 가능.

 

  1. "new Widget" 실행
  2. priority() 호출
  3. tr1::shared_ptr 생성자

 

priority()에서 예외가 발생하면?  => new Widget에서 생성된 포인터가 유실될 것이다. => 자원 누출을 막아주는 자원 관리 객체에 들어가기도 전에 예외가 발생했기 때문이다. 그래서 순서를 명확히 하기 위해 다음과 같이 해주자.

 

 

 

 

  • new 생성한 객체를 스마트 포인터에 넣는 코드는 별도의 문장으로 만들자. 이것이 되어 있으면, 예외가 발생될 디버깅하기 힘든 자원 누출이 초래될 있다.