先看一段能够正常执行的代码,但会造成内存泄漏:
deleteObject.h
实现删除一个CObjectItem的派生类的指针所指的内存
#pragma once
namespace smtlCheck
{
class CObjectItem;
class CDeleteObject
{
public:
CDeleteObject(void);
~CDeleteObject(void);
void deleteObject(CObjectItem *vObj);
};
}deleteObject.cpp
#include "deleteObject.h"
using namespace smtlCheck;
CDeleteObject::CDeleteObject(void)
{
}
CDeleteObject::~CDeleteObject(void)
{
}
void CDeleteObject::deleteObject(CObjectItem *vObj)
{
<span style="color:#ff0000;">delete vObj;</span>
}object.h
基类
#pragma once
#include <iostream>
namespace smtlCheck
{
class CObjectItem
{
public:
CObjectItem() {}
virtual ~CObjectItem()
{
//print();
}
private:
virtual void print() const = 0;//just for testing whether the deconstruction is called
};
}DivObject.h
派生类
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include "object.h"
namespace smtlCheck
{
class CDivObject : public CObjectItem
{
public:
CDivObject()
{
m_pSig = new std::string("");
m_pIntSet = new std::vector<int>[10];
}
virtual ~CDivObject()
{
delete m_pSig;
delete [] m_pIntSet;
<span style="color:#ff0000;">print();</span>
}
//other members...
private:
std::string *m_pSig;
std::vector<int> *m_pIntSet;
virtual void print() const
{
std::cout << "the deconstruction of CDivObject is called" << std::endl;
}
};
}main.cpp
#include "deleteObject.h"
#include "DivObject.h"
int main()
{
CObjectItem *pDidObj = new CDivObject;
//do something...
CDeleteObject DeObj;
<span style="color:#ff0000;">DeObj.deleteObject(pDidObj);</span>
return 0;
}运行程序会发现CDivObject的析构函数并没有调用。这时什么原因呢?
主要原因是在deleteObject.cpp这个文件里面,class CObjectItem这个类定义不完整,所以下面的代码:
void CDeleteObject::deleteObject(CObjectItem *vObj)
{
<span style="color:#ff0000;">delete vObj;</span>
}之中delete删除一个不完整定义类的指针,解决方法:
在deleteObject.cpp中加上COjectItem的头文件。但这不是一个通用的解决方法,因为这种错误很难被发现,至少是编译通过(C++中,delete一个类型不完整的类对象的指针,编译器会发出警告,不幸的是,程序员有时候会忽略这种警告),最坑人的是居然能够运行,这样的错误查找起来实在是很困难。
有没有在编译器就能够找出delete一个不完整定义的指针呢?boost就提供了一个这种功能:
boost::checkde_delete可以在编译时期发现这种错误。
修改代码如下:
void CDeleteObject::deleteObject(CObjectItem *vObj)
{
boost::checked_delete(vObj);
}加上头文件boost/checked_delete.hpp
这样我们在编译时会发现如下错误:
error C2027: use of undefined type ‘smtlCheck::CObjectItem‘
告诉我们CObjectItem类没有定义,在deleteObject.cpp的头文件中加上object.h,这样就解决问题了。
checked_delete的实现
template<class T> inline void checked_delete(T * x)
{
// intentionally complex - simplification causes regressions
typedef char type_must_be_complete[ <span style="color:#ff0000;">sizeof(T)</span>? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x;
}主要利用sizeof(T),sizeof在编译时期要知道T的大小,如果T不是一个完整的定义就会在编译是报错。
这样就可以避免delete一个不完整类型的指针。
sizeof(T)返回0的情况在有些编译器上会出现:如gcc int a[0];sizeof(a)就返回0 vs上则报错。
原文:http://blog.csdn.net/xiaoliangsky/article/details/42967823