C++中delete的时候要小心incomplete class types

缘起

The C++ Standard allows, in 5.3.5/5, pointers to incomplete class types to be deleted with a delete-expression. When the class has a non-trivial destructor, or a class-specific operator delete, the behavior is undefined. Some compilers issue a warning when an incomplete type is deleted, but unfortunately, not all do, and programmers sometimes ignore or disable warnings.


In the following example, main.cpp can see the definition of Object. However, main() calls delete_object() -- defined in deleter.cpp -- whichdoes not see the definition of Object, but only forward declares it. Callingdelete on a partially defined type like this is undefined behavior which some compilers do not flag.

在VC++下,会有

Warning C4150

Deletion of pointer to incomplete type 'type'; no destructor called

在以一般情况下,如果我们只用到Object的指针,在特定平台下Object的指针大小固定,因此编译器不会报任何错误。然而,在调用delete来删除p的时候,编译器可以知道p所指的内存大小,因为内存分配器在内存块中保存了大小信息,可以正确释放p所占据的内存。但是,由于p是Incomplete Type,编译器无法知道A所对应的析构函数(destructor),因此不会调用p的析构函数。


////////////////////
// File: deleter.hpp
////////////////////
// declares but does not define Object
class Object;
void delete_object(Object* p);
 
////////////////////
// File: deleter.cpp
////////////////////
#include "deleter.hpp"
 
// Deletes an Object without knowing its definition
void delete_object(Object* p) { delete p; }
 
////////////////////
// File: object.hpp
////////////////////
struct Object
{
  // this user-defined destructor won't be called when delete
  // is called on a partially-defined (i.e., predeclared) Object
  ~Object() {
     // ...
  }
};
 
////////////////////
// File: main.cpp
////////////////////
#include "deleter.hpp"
#include "object.hpp"
 
int main() {
  Object* p = new Object;
  delete_object(p);
}


解决办法


解决方法很简单,#include Object所在的头文件即可,如果忘记了#include,则会出现此Warning。


更彻底的方法是checked delete idiom。

The checked delete idiom relies on calls to a function template to delete memory, rather than calls todelete, which fails for declared but undefined types.

The following is the implementation of boost::checked_delete, a function template in the Boost Utility library. It forces a compilation error by invoking thesizeof operator on the parameterizing type,T. IfT is declared but not defined, sizeof(T) will generate a compilation error or return zero, depending upon the compiler. Ifsizeof(T) returns zero, checked_delete triggers a compilation error by declaring an array with -1 elements. The array name istype_must_be_complete, which should appear in the error message in that case, helping to explain the mistake.

template
inline void checked_delete(T * x)
{
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
    (void) sizeof(type_must_be_complete);
    delete x;
}
template
struct checked_deleter : std::unary_function
{
    void operator()(T * x) const
    {
        boost::checked_delete(x);
    }
};

References

http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Checked_delete

http://blog.csdn.net/ATField/article/details/1516378



你可能感兴趣的:(C++)