1. 程式人生 > >C++中的智能指針

C++中的智能指針

int ans csdn 機制 lmin 廣泛 sans else ont

眾所周知。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++中的智能指針