2009-10-23 1 views
9

다음 코드에서 개인 소멸자가있는 개체를 삭제하는 것이 가능한 방법은 무엇입니까? 실제 프로그램을 다음 샘플로 축소했지만 여전히 컴파일되고 작동합니다.개인 소멸자가있는 개체 삭제

class SomeClass; 

int main(int argc, char *argv[]) 
{ 
    SomeClass* boo = 0; // in real program it will be valid pointer 
    delete boo; // how it can work? 

    return -1; 
} 

class SomeClass 
{ 
private: 
    ~SomeClass() {}; // ! private destructor ! 
}; 
+0

내가 위의 클래스의 정의를 이동 Interesting..if 주() 다음은 컴파일러 오류가 발생합니다. 그렇지 않으면, 나는 단지'경고 C4150 : 불완전한 타입 'SomeClass'에 대한 포인터 삭제; '소위 말하는 소위가 없습니다. – Naveen

+1

@ Naveen : 예상대로입니다. 불완전한 유형이 한 가지 문제입니다. 개인 소멸자는 또 다른 소멸자입니다. 각각에는 자체 진단 메시지가 있습니다. 'SomeClass'의 정의를 옮겨서 둘 사이를 전환합니다. – AnT

답변

15

:

예를 들어, g ++는 당신에게이 문제에 대한 경고를 줄 것이다. C++ 표준은이 경우 (5.3.5/5)에 정의되지 않은 동작을 얻을 것이다 말한다 :

삭제되는 개체가 삭제 및 전체 클래스의 시점에서 불완전한 클래스 유형이있는 경우가 아닌 사소한있다

소멸자 또는 할당 해제 함수의 경우 동작이 정의되지 않습니다.

boost::checked_delete을 사용할 수 이러한 경우를 감지하려면

template<typename T> 
inline void checked_delete(T* p) 
{ 
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; 
    (void) sizeof(type_must_be_complete); 
    delete p; 
} 
+1

이것은 빈 구조체/클래스의 경우에도 sizeof()가 0을 반환하지 않음을 이용합니다. 잊어 버렸습니다. ISO-IEC-14882 섹션 9.1 : "클래스 타입의 완전한 객체와 멤버 서브 객체는 0이 아닌 크기를 가져야한다." 배열의 모든 객체는 고유 한 메모리 주소를 갖게됩니다. 아마도 구조체에 대해서도 마찬가지입니다 - C에서도 그렇습니까? – leander

+0

빈 구조체의 C 크기는 0과 같습니다. –

+0

@leander : 정확하게는 아닙니다. C++에서 불완전한 타입에'sizeof'를 적용하는 것은 단순히 불법 *입니다. 이것은 위의 코드가'(void) sizeof ... '부분에 잡으려고하는 것입니다. 이 표현식은 * 오류 *를 발행하여 표준을 준수하는 컴파일러에서 컴파일을 중지해야합니다. 그러나 이상한 컴파일러가 불완전한 타입 (확장자로)에 0을 넣을 때'sizeof'를 허용하면'typedef ... '부분이이를 catch하고 "음의 크기의 배열"오류를 발생시킵니다. 그래서, 여기에는 메인 ("void") 부분과 "just in case"('typedef' 부분)라는 보조 트랩이 있습니다. – AnT

7

이 코드는 정의되지 않은 동작 (UB)을 발생시킵니다. C++의 UB에서 delete까지는 사소한 소멸자가있는 불완전한 유형의 객체입니다. 그리고 코드에서 타입은 delete의 시점에서 불완전하며, 사소한 소멸자가 있습니다. 컴파일러는 일반적으로 C++에서 공식적으로 이것은 제약 조건 위반이 아니기 때문에 이것에 대한 경고를 발행합니다.

엄밀히 말하자면 코드는 "작동하지"않습니다. 을 컴파일하고 실행하면 은 정의되지 않음을 수행합니다.

컴파일러는이 오류를 catch 할 필요가 없습니다. 그 이유는 객체가 소멸자 소멸자를 가지고 있다면 완벽하게 괜찮을 수 있기 때문입니다. 컴파일러는이 유형의 소멸자가 결국 어떤 종류의 소멸자인지 알 수 없으므로 이것이 오류인지 여부를 확실히 말할 수 없습니다.

+0

'(1)'T'가 사소한 소멸자를 가졌다면 괜찮을 것입니다. (2)'T'는'delete operator'를 다시 정의하지 않습니다. – curiousguy

4

operator delete을 호출 할 때 SomeClass 유형이 완전히 선언되지 않았기 때문에.

그러한 포인터를 삭제하는 것은 정의되지 않은 동작이지만 실제로는 대부분의 컴파일러가 포인터가 NULL이 아닌 경우 메모리를 해제하고 소멸자를 호출하지 않습니다. 당신은 불완전한 클래스 형식의 개체를 삭제하려고

foo.cpp: In function 'int main(int, char**)': 
foo.cpp:6: warning: possible problem detected in invocation of delete operator: 
foo.cpp:5: warning: 'boo' has incomplete type 
foo.cpp:1: warning: forward declaration of 'struct SomeClass' 
foo.cpp:6: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined. 
+1

"포인터를 지우면 그냥 메모리를 비울 것입니다 ..."- NO! 동작은 * UNDEFINED *입니다. 즉 "본질적으로"발생하는 것에 대한 모든 가정은 유효하지 않습니다. – DevSolar

+1

@DevSolar : True, 표준에 따라 정의되지 않았습니다. 실제로 이것은 대부분의 컴파일러에서 발생합니다. 이를 반영하기 위해 답변을 업데이트했습니다. – laalto

+0

나는 잘 행동 한 영역 밖에있는 것에 의존하는 것에 다소 문제가있다. 특히 동료의 코드에서. 그것은 나를 벽으로 몰아 넣는다. 나는 네 답을 비난한다. (;-) << - important smiley) – DevSolar