2011-01-17 2 views
4

이 코드가 있다고 가정 해보자 :생성자에서 예외가 발생하면 객체에 할당 된 메모리가 자동으로 삭제됩니까?

class CFoo 
{ 
public: 
    CFoo() 
    { 
     iBar = new CBar(); 
    } 
private: 
    CBar* iBar; 
}; 

.... 
CFoo* foo = new CFoo(); 

위의 라인이 실행될 때, 첫 번째 메모리는 CFoo 객체를 담기 위해 할당 될 것이다. 그러나 새로운 CBar() 라인이 메모리 부족으로 인해 예외를 던지면 시스템은 이전에 CFoo 객체에 할당되었던 메모리를 자동으로 할당 해제합니까? 필자는 그럴 필요가 있다고 말하지만 명시 적 참조는 찾을 수 없습니다. 그것이 foo에 할당되지 않았 으면 어떻게 코더에 의해 메모리가 할당 해제 될 수 있습니까?

+2

참조 : http://stackoverflow.com/questions/810839/throwing-exceptions-from-constructors 및 http://stackoverflow.com/questions/ 1230423/c-handle-resources-if-constructors-may-throw-exceptions-faq-17 및 http://stackoverflow.com/questions/1197566/is-it-ever-not-safe-to- throw-an-exception-in-a-constructor – user470379

+0

예외가있는 경우 메모리가 할당되지 않았다고 생각합니다. – Elalfer

+2

이전 5 가지 질문에 대한 대답 중 일부를 받아 들일 수 있습니다. –

답변

6

는 예, CFoo 객체에 할당 된 메모리가이 경우에 해제됩니다 new 연산자의 다음과 같은 간단한 의사를 고려하십시오.

실패한 할당으로 인해 예외가 성공적으로 새로운 표현을 완료하는 데 실패 할 CFoo 생성자가 발생하기 때문에

CFoo 객체에 할당 된 메모리를 무료로 보장된다.

이 보증은 ISO/IEC 14882 : 2003의 5.3.4 [expr.new]/17에 명시되어 있습니다.

올바른 정리를 위해 항상 동적 할당 결과를 스마트 포인터에 할당하는 것이 좋습니다. 예를 들어, CFoo 생성자에 추가 코드가 있고 예외가 발생하면 CBar 개체가 이미 생성자에서 이전에 성공적으로 할당 된 이전에 누출 될 수 있습니다.

1

예 - 메모리가 자동으로 해제됩니다.

template<typename T> T* operator new() { 
    void* ptr = nullptr; 
    try { 
     ptr = ::operator new(sizeof(T)); 
     return new (ptr) T(); 
    } catch(...) { 
     ::operator delete(ptr); 
     throw; 
    } 
} 
+1

이 코드는 "의사"코드라는 것을 알고 있지만 오해의 소지가 있다고 생각합니다. 연산자 new라고 부르지 만 operator new와는 아무런 관계가 없으므로 새로운 배치가 아닌 새로운 expression_ preform을 복제합니다. 그것은'malloc'을 사용하지만 _new-expression_ **는'operator new'를 사용해야합니다.'static_cast'는 불필요합니다. 배치 된 새로운 표현식은 생성되는 타입에 대해 올바르게 입력 된 포인트로 평가됩니다. –

+0

"의사"가 "단순화 된"것보다 더 중요합니다. 위의 유일한 중요한 동작은 예외와 관련하여 작동하는 방식입니다. 그러나 malloc/free를 사용하는 것은 실수였습니다. – Puppy

+0

실제로 반환되는 유형에 상관없이 새로운 void 포인터를 반환하지 않아야합니까? 네임 스페이스에 순환 참조가 있습니다. – wheaties

0

컴파일러가 제공하는 연산자 new에 의존한다면 위의 경우 소멸자가 호출되지 않습니다. 그 이유는 : 새로운 CBar()가 예외를 던지면, 스택 풀기가 즉시 일어나기 시작하고, 객체 CFoo가 "완전히"생성되지 않기 때문입니다. 객체가 반 생성되었으므로 컴파일러는 CFoo에 대한 소멸자를 호출하지 않습니다. 엄지 손가락의

규칙 : 소멸자는 C에서 완전히 구성 객체 ++

+0

질문은 소멸자가 호출되는지 여부가 아니라 객체의 메모리가 할당 취소되는지 여부를 묻는 것입니다. 객체가 아직 생성되지 않았기 때문에 소멸자가 호출되지 않아야합니다. –

+0

알았어요. :-) 고맙습니다! – Viren

+1

사실, 모든 하위 객체는 * 생성 된 * 생성자를 가지게됩니다 :'struct test {test() : a(), b(), c() {} a, b, c; }'c()'생성자가 던져지면, 소멸자가 호출되지 않고 어느 쪽도 소멸자를'test'하지 않지만'a'와'b' 소멸자는 호출 될 것입니다. 예외가 throw됩니다. –

3

예에 대해서만라고하지만, 더 이상의 멤버 포인터가 있다면 무슨 생각됩니다 : 이제 CBAR 객체가 유출 될

class CFoo 
{ 
public: 
    CFoo() 
    { 
     iBar = new CBar(); 
     iBaz = new CBaz(); // Throws an exception 
    } 
private: 
    CBar* iBar; 
    CBaz* iBaz; 
}; 

.... 
CFoo* foo = new CFoo(); 

. 네이티브 포인터 대신 스마트 포인터를 사용하면이 문제를 해결할 수 있습니다.

또한, 멤버 이니셜 라이저를 사용하는 것을 선호 :

class CFoo 
{ 
public: 
    CFoo() : iBar(new CBar()) 
    { 
     // Nothing here 
    } 
private: 
    CBar* iBar; 
}; 

.... 
CFoo* foo = new CFoo(); 
관련 문제