举个例子来说明:
//=================================================================
//DeleteObject.h
class Item;
class DeleteObject
{
public:
DeleteObject(void);
public:
~DeleteObject(void);
void DeleteItem(Item* p);
};
//=================================================================
//DeleteObject.cpp
#include "StdAfx.h"
#include "DeleteObject.h"
#include <boost/checked_delete.hpp>
DeleteObject::DeleteObject(void)
{}
DeleteObject::~DeleteObject(void)
{}
void DeleteObject::DeleteItem( Item* p )
{
delete p;
}
//=================================================================
//item.h
#include <iostream>
class Item
{
public:
~Item()
{
std::cout<<"Item destruction ";
}
};
//=================================================================
//main.cpp
#include "DeleteObject.h"
#include "Item.h"
int main(int argc,char** argv)
{
DeleteObject del;
del.DeleteItem(new Item);
Return 0;
}
//=================================================================
结果Item的析构函数没有被调用!!!!!
这是因为DeleteObject并不知道Item的详细定义,这是C++中一个很危险的错误!(还好编译器一般都给warning)
怎么解决这个问题呢?
我们知道,对于不完整类型的指针:
class incomplete;
incomplete* p;
delete p;
在这里,p并未指向一个实例且未指向0,因此delete p是危险的,但根据编译器不同,这里可能只会给出一个warning而不是error。因此,可以:
template <class T> inline void checked_delete(T * x)
{
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x;
}
cheched_delete代码中利用了“typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];”,当p未指向实例时,sizeof(T)给出的是0,根据代码规则,-1是不能作为数组的size的,因此,这里相当于强制编译器给出error而不是 warning。
还有一个最简单的测试:
C/C++ code
// 此处T是不完整类型 , 编译会出错
typedef char T[];
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
// 此处T是完整类型 , 编译不会出错
typedef char T[1];
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);