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++中的智能指針