2012-02-03 2 views
17

저는 C++의 RAII 숙어와 스마트 포인터를 사용하는 방법에 대해 배우고 있습니다.생성자가 예외를 throw 할 때 RAII는 어떻게 작동합니까?

제 독서에서, 저는 두 가지를 보았습니다. 그것은 저에게 서로 모순되는 것처럼 보입니다. http://www.hackcraft.net/raii/에서 인용

:

... RAII 의미와 부재 오브젝트가 작성되어 생성자 다음 소멸자가 풀림 스택의 일부로서 호출된다 완료되기 전에 예외가 발생 된 경우. 따라서 여러 리소스를 제어하는 ​​객체가 멤버 RAII 객체를 사용하여 완전히 구성되지 않은 경우에도 해당 객체를 정리할 수 있습니다.

그러나 인용 http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10에서 :

생성자가 예외를 throw했을 경우, 객체의 소멸자가 실행되지 않습니다. 개체가 이미 수행해야하는 작업 (예 : 메모리 할당, 파일 열기 또는 세마포 잠금)을 수행 한 경우이 "작업을 취소해야하는 작업"은 개체 내부의 데이터 멤버가 기억해야합니다.

그런 다음 두 번째 연결된 소스는 스마트 포인터를 사용하여 생성자에 이미 할당 된 항목의 문제를 처리 할 것을 권장합니다.

그래서 실제로 이러한 시나리오에서 어떻게됩니까?

+8

+1 이것은 "newprogrammer [s]"*가 질문해야하는 방식입니다! –

답변

11

첫 번째 따옴표를 오해하고 있습니다. 혼란 스럽기 때문에 어렵지 않습니다.

RAII 의미와 부재 객체가 생성되고 그 후 생성자 소멸자 스택 풀림의 일부로서 호출된다 완료되기 전에 예외가 발생 된 경우.

그건 뭐니? 여기 무엇을 의미 : RAII 의미를 가진 구성원 객체가 생성 된 경우

를 예외는 외부 개체의 생성자는 다음 구성원 개체의 소멸자가됩니다 완료되기 전에 외부 객체에 을 발생 스택 되감기의 일부로 호출 될 수 있습니다.

차이점을 확인 하시겠습니까? 아이디어는 멤버 객체가 생성자를 완성했지만 소유 유형은 생성자 객체가 아닙니다.그것은 생성자 (또는 그 다음에 초기화되는 다른 멤버의 생성자)의 어딘가에서 던졌습니다. 이로 인해 모든 멤버의 소멸자가 호출되고 (즉, 완료된 모든 것), 자체 소멸자가 아닙니다. 당신이 SomeType 인스턴스를 만들 때

class SomeType 
{ 
    InnerType val; 
public: 
    SomeType() : val(...) 
    { 
    throw Exception; 
    } 
}; 

, 그것은 InnerType::InnerType를 호출합니다 :

다음은 예입니다. 그것이 던지지 않는 한, SomeType의 생성자를 입력합니다. 그걸 던지면 val이 파괴되어 InnerType::~InnerType이 호출됩니다.

+1

아, 그 말이 맞습니다 ... 그건 그렇고, 당신은 멋진 3D 그래픽 가이드를 작성한 사람입니까? 그 가이드가 얼마나 위대한 지에 대해 충분히 고마워 할 수는 없습니다. – newprogrammer

+3

"이것은 소멸자가 아닌 모든 소속 구성원의 소멸자가 호출되도록합니다." - 글쎄, 예외가 던져지기 전에 공사를 완료 한 사람 만이 .... –

2

이 두 문장은 서로 모순되지 않지만 첫 번째 문장은 불행한 언어입니다. 어떤 객체의 생성이 던질 때, 그것은 deconstructor가 호출되지 않을 것이지만, 그 객체가 소유 한 모든 객체는 각각의 deconstructor에 의해 파괴 될 것입니다.

따라서 RAII 및 스마트 포인터를 사용하면 객체의 포인터 멤버에 대한 소멸자가 소유 객체의 소멸자와 독립적으로 호출됩니다. 원시 포인터는 가리키는 메모리를 해제하지 않으므로 수동으로 삭제해야합니다. 소유 객체의 생성자가 원시 포인터를 던져서 해제되지 않아야합니다. 이것은 스마트 포인터에서 발생할 수 없습니다.

5

여기에는 모순이 없습니다. 다른 컨텍스트에서 사용되는 혼동되는 용어가 있습니다. 객체의 생성자가 예외를 throw하면

, 그 다음은 (예외를 가정하면 잡힌) 발생

  1. 생성자의 모든 지역 변수가 소멸자들이 획득 한 모든 리소스를 해제, 호출 한 (있는 경우 어떤).
  2. 생성자가 예외를 던진 객체의 모든 직접 하위 객체는 소멸자가 호출되어 획득 한 자원을 해제합니다. 발신자 등의
  3. 또한 정리 생성자 소멸자를해야합니다 던졌다 호출 (파생 클래스 생성자가 실행하기 전에이 완벽하게 구축 된 이후) 객체의
  4. 모든 기본 클래스가 개최됩니다. 그 결과

, 개체의 소멸자 정리를 할 스마트 포인터 또는 데이터가 참으로 정리됩니다 파괴되는 객체의 구성원 인 다른 RAII 객체 만, 전문 코드에 의해 관리되는 모든 자원 원 화재.

희망이 도움이됩니다.

+0

네 단계 설명에 의해 귀하의 단계는 모든 것을 정리했습니다! – newprogrammer

관련 문제