2010-05-17 6 views
13

boost :: checked_delete의 목적을 이해하지 못합니다./5 5.3.5가, 불완전 클래스 유형 포인터가 삭제 표현과 삭제에,boost :: checked_delete 목적

C++ 표준이 있습니다 : 문서를 말한다. 클래스에 소멸자 소멸자가 있거나 클래스 별 연산자 삭제가있는 경우 동작은 으로 정의되지 않습니다. 일부 컴파일러에서는 불완전 유형이 일 때 경고를 발행하지만, 불행히도 이 모두있는 것은 아니며 프로그래머가 을 무시하거나 경고를 비활성화 할 수 있습니다.

제공되는 기능과 클래스 템플릿은 완전한 유형을 필요로,이 문제를 방지하고, 그렇지 않으면 컴파일 오류 을 야기 할 수 있습니다.

따라서 C++ 표준에서는 형식이 중요하지 않은 소멸자가있는 경우 정의되지 않은 동작을 일으키는 불완전한 형식을 삭제할 수 있습니다. 뭐? 불완전한 타입은 어떻게 소멸자를 가질 수 있습니까? 불완전한 유형이 단지 프로토 타입이 아닌가?

// this file does not include the definition of foo 

class foo; 

void bad(foo *f) 
{ 
    delete f; // undefined behavior if there exists foo::~foo 
} 

현실에서, foo는의 정의는 다음과 같이 보일 수 있습니다 :

+0

슬라이스와 관련이 있습니까? http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c – Cogwheel

답변

16

불완전한 유형의 가장 일반적인 예는 선언 된 하나입니다

class foo 
{ 
public: 
    ~foo() { ... }; 
}; 

그러나 상단 경우 코드가 클래스 정의를 '보지'않고 클래스 선언 만 보게되면 코드가 컴파일됩니다.

+0

클래스 템플릿에서 완전한 유형을 * 요구할 수 있습니까? –

+3

'checked_delete'는 타입에'sizeof'를 호출하려고 시도합니다. 타입이 불완전하면 컴파일러 에러가 발생합니다. – Channel72

+0

@ Channel72 : 왜 C++이 이것을 컴파일러 오류로 정의하지 않는지 알고 있습니까? –

2

C++에서는 불완전한 유형을 가리키는 변수에 delete을 사용할 수 있습니다.

struct S; // incomplete 

int main() { 
    S* s = NULL; 
    delete s; // legal 
} 

컴파일러는 실제로 S이 무엇인지 알지 못합니다. S에 사소한 소멸자가없는 것으로 판명되면 컴파일러는 해당 문제를 감지 할 필요가 없습니다.

사실상 컴파일러가 불완전한 유형의 delete 명령어를 발견하면 유형의 일반 컴파일러 - 기본 소멸자 생성을 기대하는 호출을 채 웁니다. 그것이 소멸자가되는 것으로 밝혀지면 모든 것이 정상입니다. 그러나 S에 사소한 소멸자가 없거나 자체의 특별한 삭제 방법을 제공하는 경우 컴파일러가 이전에 채운 내용이 잘못 될 수 있습니다. 그러나 컴파일러는 정확히 delete 명령어를 컴파일하고 뒤돌아 보지 않는다고 가정 할 수 있습니다. 이 가정이 틀리면 정의되지 않은 동작이 발생합니다.

부스트 기능을 사용하면 완전한 유형에서만 호출되므로 불완전한 유형에서 발생할 수있는 정의되지 않은 동작을 피할 수 있습니다.

Foo.h :

4

는 다음과 같은 고려

#ifndef Foo_H 
#define Foo_H 
#include <boost/scoped_ptr.hpp> 
#include <boost/utility.hpp> 

class Foo : private boost::noncopyable 
{ 
public: 
    Foo(); 
    ~Foo(); 

    void do_something_interesting(); 

private: 
    class Impl; // incomplete type 
    boost::scoped_ptr<Impl> impl; 
}; 

#endif 

푸.CPP : 유형이 불완전하기 때문에이 (인위적인) 예를 감안할 때

#include "Foo.h" 
#include <string> 
#include <iostream> 

class Foo::Impl 
{ 
public: 
    Impl() : name("Foo::Impl") 
    {} 

    void say_hi() 
    { std::cout << name << " says hi!" << std::endl; } 

    std::string name; 
}; 

Foo::Foo() 
: impl(new Impl) 
{} 

Foo::~Foo() 
{} 

void Foo::do_something_interesting() 
{ impl->say_hi(); } 

, 당신은 Foo::Foo 또는 Foo::~Foo 중 하나를 인라인 할 수 없습니다. 유형 Foo::Impl이 완전한 유형 인 컨텍스트에서 두 유형을 모두 정의하면 유형을 안전하게 삭제할 수 있습니다. boost::checked_delete이 안전 점검을 수행하며 이는 순전히 컴파일 시간 비용입니다. Foo::~Foo을 인라인하거나 완전히 생략하면 Foo 인스턴스를 파괴하려고 시도 할 때마다 boost::checked_delete에서 오류가 발생합니다.