指針是C++從C繼承過來的一個強大而有效的工具,指針被人诟病的地方有很多,其中內存管理的艱難性就是其中之一。比如一個在堆中維護的對象,有好幾個指針都指向它,那麼究竟由誰來負責釋放內存呢?小程序還好說,大程序往往很難理清其中的邏輯,一個處理不好就會造成內存洩露這樣的嚴重問題。
智能指針就是這樣一種實現機制,它通過一種引用計數器的實現原理,來保證由最後一個指向該對象的指針負責釋放內存,將管理內存的工作交由指針自己去完成,減輕了程序的員的負擔。下面我們來手動完成一個智能指針的實現:
SmartPointer.h文件
[cpp]
/*
*author: justaipanda
*create time:2012/07/23 15:05:00
*/
#ifndef _SMARTPOINTER_H
#define _SMARTPOINTER_H
#include <stdexcept>
using namespace std;
/*
*description:
* this template class is used as a smart pointer handler
* which can manage the allocated memory
*/
template<class T>
class SmartPointer {
public:
SmartPointer(T* p_ptr = NULL):ptr(p_ptr),
count(new size_t(1)) {
}
SmartPointer(const SmartPointer& sp):ptr(sp.ptr),
count(new size_t(sp.count)) {
++*count;
}
SmartPointer& operator=(const SmartPointer& sp);
bool operator==(const SmartPointer& sp) const {
return ptr == sp.ptr;
}
T& operator*() const {
if (ptr)
return *ptr;
else
throw logic_error("unbunded pointer");
}
T* operator->() const {
if (ptr)
return ptr;
else
throw logic_error("unbunded pointer");
}
~SmartPointer() {
destroy();
}
private:
T* ptr;
size_t* count;//used to recorde the reference times
void destroy();
};
#include "SmartPointer.cpp"
#endif
SmartPointer.cpp文件
[cpp]
/*
*author: justaipanda
*create time:2012/07/23 15:30:15
*/
template<class T>
SmartPointer<T>& SmartPointer<T>::operator=(
const SmartPointer& sp) {
if (ptr != sp.ptr) {
destroy();
ptr = sp.ptr;
count = sp.count;
++*count;
}
return *this;
}
template<class T>
void SmartPointer<T>::destroy() {
if (--*count == 0) {
delete ptr;
delete count;
}
}
由於我們定義的實際上是一個類模板,所以,頭文件必須要包含實現文件。
現在我們來看一下程序實現的細節。
在SmartPointer的內部維護了兩個指針,一個用於指向所管理的堆中的對象,另一個則是引用計數器。在構造函數中,count被初始化為1,而每當發生復制時,例如拷貝構造函數被調用,或是=運算符被使用,都會導致該計數器加1。而每當智能指針被賦以新值,或該指針本身被銷毀時,它都會將引用數減1,然後判斷是否為0,如是,則銷毀對象。這一部分代碼被重構出來是因為賦值重載函數和析構函數都會使用到這一邏輯,在類的內部有一個私有函數destroy專門負責這一部分功能。
通過引用計數器保證了指針的安全性。其他的代碼就是保證我們智能指針的可用性了,它將使我們使用智能指針和普通指針一樣的方便。指針最主要的功能就是解引用以及執行運算符了,所以重載了這兩個運算符就能保證這一點。解引用的邏輯比較簡單,我們主要分析一下對指向運算符的重載:
[cpp]
T* operator->() const {
if (ptr)
return ptr;
else
throw logic_error("unbunded pointer");
}
可以看見,它實際上也沒做額外的工作,就是在保證指針綁定到一個特定的對象的情況下返回它所維護的指針而已,這裡面包含著一個重要的編譯特性。先看一個使用智能指針的例子:
[cpp]
/*
*author: justaipanda
*create time:2012/07/23 15:38:19
*/
#include <iostream>
#include "SmartPointer.h"
using namespace std;
class A {
public:
void test() {
cout<< "this is a test function"<< endl;
}
};
int main() {
SmartPointer<A> ptr(new A());
ptr->test();
return 0;
}
注意看調用語句ptr->test();實際上,編譯器在編譯這條語句時做了特殊的處理,編譯器在遇到指向運算符時如果發現調用者是一個重載了指向運算符的類,而並非一個普通的指針,它將做如下替換:
[cpp] view plaincopy
(ptr->)->test(); www.2cto.com
這樣就保證了我們可以正常使用我們的智能指針,而且這種機制是遞歸的,也就是說,如果指向運算符返回的仍是一個重載了指向運算符的類,而非普通的指針,那麼它將做遞歸的替換。好了,重點的就說這麼多吧。