boost::checked_delete

先看一段能够正常执行的代码,但会造成内存泄漏:

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上则报错。

时间: 2024-11-08 22:03:15

boost::checked_delete的相关文章

Boost源码学习---scoped_ptr.hpp

scoped_ptr是一个智能指针,包装了指向堆上内存的指针.它对指针所有权加以限制,不能转让指针所有权,一旦scoped_ptr获取了指针的管理权,便不再释放,无法再从其取回来,就像scope意思一样,指针智能在作用域使用,不能转让出去.一旦离开scoped_ptr的作用域,将调用它的析构函数,释放指针,不用手动释放.下面是它的源代码: #ifndef BOOST_SMART_PTR_SCOPED_PTR_HPP_INCLUDED #define BOOST_SMART_PTR_SCOPED_

Boost源码学习---

scoped_array功能类似scoped_ptr,scoped_array管理的是new[]开辟的数组,其析构函数调用的是delete[]释放数组. 它没有重载解引用*和箭头操作符->,因为它不是普通指针,而是一个数组.它重载了[],可以像使用数组下标那样访问数组. #ifndef BOOST_SMART_PTR_SCOPED_ARRAY_HPP_INCLUDED #define BOOST_SMART_PTR_SCOPED_ARRAY_HPP_INCLUDED // (C) Copyrig

checked_delete/checked_array_delete

在boost的智能指针中析构时都用到了checked_delete 和checked_array_delete,为什么不简单地delete呢? 在头文件"boost/checked_delete.hpp"定义了两个函数模板,checked_delete 和 checked_array_delete, 以及两个类模板,checked_deleter 和 checked_array_deleter.他们作用是什么呢? 官方解释: C++标准的 5.3.5/5 节中允许通过一个 delete

Boost scoped_ptr scoped_array 以及scoped_ptr与std::auto_ptr对比

boost::scoped_ptr和std::auto_ptr非常类似,是一个简单的智能指针,它能够保证在离开作用域后对象被自动释放.下列代码演示了该指针的基本应用: #include <string> #include <iostream> #include <boost/scoped_ptr.hpp> class implementation { public: ~implementation() { std::cout <<"destroyi

Chapter 10-01

Please indicate the source: http://blog.csdn.net/gaoxiangnumber1 Welcome to my github: https://github.com/gaoxiangnumber1 ?C++语言的三大约束是:与C兼容.零开销(zero overhead)原则.值语义.§11.7介绍值语义. ?"与C兼容"不仅仅是兼容C的语法,更重要的是兼容C语言的编译模型与运行模型,也就是说能直接使用C语言的头文件和库. ?比方说对于con

关键字:__thread &amp; pthread_key_t

在说__thread之前,先来看看pthread_ket_t吧. 参考:http://blog.csdn.net/lmh12506/article/details/8452700 上面的博文说的比较通俗易懂.线程私有数据可以理解为线程内的全局变量.在线程内可以被所有函数访问,但是不能被其他线程的函数访问. 这里博主直接去找pthread.h头文件中的API,发现写的还是很详细的. /* Functions for handling thread-specific data. */ //用于处理线

Boost 1.61.0 Library Documentation

http://www.boost.org/doc/libs/1_61_0/ Boost 1.61.0 Library Documentation Accumulators Framework for incremental calculation, and collection of statistical accumulators. Author(s): Eric Niebler First Release: 1.36.0 Standard: Categories: Math and nume

所有的 Boost 库文档的索引

按字母顺序列出的库 按类别列出的库 算法 破碎的编译器的解决方法 并发编程 容器 正确性和测试 数据结构 特定于域的 函数对象和高阶编程 泛型编程 图像处理 输入/输出 跨语言支持 迭代器 语言功能仿真 数学和数字 内存 解析 模式和习语 预处理器元编程 编程接口 状态机 字符串和文本处理 系统 模板元编程 杂项 图书馆从提高退休 请参阅入门页面以了解如何下载. 构建和安装库. 按字母顺序列出的库 蓄能器-增量计算和统计累加器,Eric Niebler 从集合框架 算法-有用的通用算法,从马歇尔

mac下编译 boost编译工具b2

cd boost_1_64_0/tools/build ./bootstrap.sh --with-toolset=gcc 输出: -n Bootstrapping the build engine with toolset gcc... engine/bin.macosxx86_64/b2 Bootstrapping is done. To build and install, run: ./b2 install --prefix=<DIR> ./b2 install --prefix=/u