C++中的智能指针

众所周知,C++中对堆内存的申请与释放完全由用户来控制,这就造成用户在使用的时候经常造成内存泄漏、野指针、重复释放等常见的挂掉问题,所以我们有必要提供一套机制,使得用户只需申请相应的内存,不用管释放的问题,其实这属于著名的RAII(Resource Acquisition Is Initialization)技术 。在C++中这种技术称作“智能指针”,C++中的智能指针技术越来越受到广泛应用。下面简要介绍下智能指针。


从以上描述中可以看出,我们需要提供一套内存显式申请与隐式释放,并向用户屏蔽这些细节的机制,对于这种隐藏细节的做法,我们通常会用一个句柄类来封装。在这里句柄类就是我们提供给用户的智能指针类。

智能指针为何“智能”呢?这里就涉及到另一项重要技术”引用计数“,当有N个智能指针句柄类指向同一段内存,这时就会将这段内存的引用计数设置为N,每当其中的一个句柄离开作用域时会自动调用析构函数,将内存引用计数减一,这样当某个智能指针句柄类的引用计数为1时,表示这段内存只有该句柄指向它。在这个过程中,析构函数起很大的作用,RAII技术也是基于析构函数而实现的。

说了这么多,直接看代码:

/*
 * refcount.h  引用计数
 *	[email protected]
 */
#ifndef _REFCOUNT_H_
#define _REFCOUNT_H_

class RefCount
{
public:
	RefCount() : use(new size_t(1)){}
	RefCount(const RefCount &refcnt) : use(refcnt.use)
	{
		inc();
	}
	~RefCount()
	{
		if (decr() == 0)
		{
			delete use;
		}
	}
	RefCount & operator=(const RefCount &refcnt)
	{
		if (decr() == 0)
		{
			delete use;
		}
		use = refcnt.use;
		inc();
		return *this;
	}

	void init()
	{
		use = new size_t(1);
	}

	bool only()
	{
		return *use == 1;
	}

	inline size_t inc()
	{
		return ++*use;
	}

	inline size_t decr()
	{
		return --*use;
	}

	bool reattach(const RefCount &refcnt)
	{
		++*refcnt.use;
		if (only())
		{
			delete use;
			use = refcnt.use;
			return true;
		}
		else
		{
			--*use;
			use = refcnt.use;
			return false;
		}
	}

private:
	size_t *use;
};

#endif  //  _REFCOUNT_H_

/*
 * smartpointer.h  智能指针
 *	[email protected]
 */
#ifndef _SMARTPOINTER_H_
#define _SMARTPOINTER_H_

#include "refcount.h"

template <typename T>
class SmartPtr
{
public:
	SmartPtr() : ptr_(new T)
	{
		refcnt_.init();
	}

	SmartPtr(const T & obj) : ptr_(new T(obj)){}
	
	SmartPtr(T * pobj) : ptr_(pobj)
	{
		//refcnt_初始化时,*use = 1
		if (pobj == nullptr)
		{
			refcnt_.decr();
		}		
	}

	SmartPtr(const SmartPtr &spnt) : ptr_(spnt.ptr_), refcnt_(spnt.refcnt_){	}

	~SmartPtr()
	{
		if (refcnt_.only())
		{
			delete ptr_;
			ptr_ = nullptr;
		}		
	}

	SmartPtr & operator=(const SmartPtr &spnt)
	{
		//这一步相当于对refcnt_进行赋值
		if (refcnt_.reattach(spnt.refcnt_))
		{
			delete ptr_;
		}
		ptr_ = spnt.ptr_;
		return *this;
	}

	T * operator->()
	{
		return ptr_;
	}

private:
	T * ptr_;
	RefCount refcnt_;
};

#endif  //  _SMARTPOINTER_H_

/*
 * main.cpp  测试程序
 *	[email protected]
 */
#include "memleakcheck.h"
#include "smartpointer.h"
#include <iostream>
#include <string>
#include <boost/shared_ptr.hpp>

int main(void)
{
	{
		SmartPtr<int> sp(2);
		SmartPtr<int> sp2(sp);
		SmartPtr<int> sp3(3);
		sp = sp3;
		sp2 = sp3;
	}	

	{
		SmartPtr<std::string> sp("123");
		SmartPtr<std::string> sp2(sp);
		SmartPtr<std::string> sp3("abc");
		sp = sp3;
		sp2 = sp3;
	}	

	{
		SmartPtr<std::string> sp(new std::string("123"));
		SmartPtr<std::string> sp2(sp);
		SmartPtr<std::string> sp3(new std::string("abc"));
		sp = sp3;
		sp2 = sp3;
	}	

	{
		boost::shared_ptr<char> pch(new char[10]);
	}
	_CrtDumpMemoryLeaks();

	return 0;
}

memleakcheck.h文件主要用作VS平台内存泄漏检测工具,代码参考于http://blog.csdn.net/windows_nt/article/details/8652191

调试时,发现输出窗口并没有检测到内存泄漏,说明智能指针实现正确。main.cpp中还测试了Boost库中智能指针的使用,可以看到也是很方便的,目前在开源点云库PCL中随处都可见到Boost库中的智能指针。


以上代码见github:https://github.com/lming08/Ruminations/


参考资料:

http://www.cnblogs.com/zhangyunkui/archive/2009/11/13/1602514.html

http://blog.csdn.net/windows_nt/article/details/8652191

C++沉思录

你可能感兴趣的:(C++,内存泄漏,智能指针)