C++中的智能指针

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


从以上描写叙述中能够看出,我们须要提供一套内存显式申请与隐式释放,并向用户屏蔽这些细节的机制,对于这样的隐藏细节的做法。我们一般会用一个句柄类来封装。

在这里句柄类就是我们提供给用户的智能指针类。

智能指针为何“智能”呢?这里就涉及到还有一项重要技术”引用计数“。当有N个智能指针句柄类指向同一段内存,这时就会将这段内存的引用计数设置为N,每当当中的一个句柄离开作用域时会自己主动调用析构函数。将内存引用计数减一,这样当某个智能指针句柄类的引用计数为1时,表示这段内存仅仅有该句柄指向它。

在这个过程中。析构函数起非常大的作用,RAII技术也是基于析构函数而实现的。

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

/*
 * refcount.h  引用计数
 *	lming_08@hotmail.com
 */
#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  智能指针
 *	lming_08@hotmail.com
 */
#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  測试程序
 *	lming_08@hotmail.com
 */
#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++沉思录

posted @ 2017-05-30 08:41  jzdwajue  阅读(130)  评论(0编辑  收藏  举报