用c++簡單實現智能指針
什麼是智能指針?答案相當簡單;智能指針是聰明的普通指針。這是什麼意思?實際上,智能指針是一些對象,表現出普通指針的功能但是比普通指針多做了一些事情。這些對象像普通指針一樣靈活,並且管理對象有自己的優點(比如構造器和自動析構)。智能指針解決了普通指針的一些問題。
普通指針的問題。
我們使用C++語言中的指針,最常見的問題是什麼?內存管理吧,請看下面的代碼:
[cpp]
char* pName = new char[1024];
…
SetName(pName);
…
…
if(null != pName)
{
delete[] pName;
}
char* pName = new char[1024];
…
SetName(pName);
…
…
if(null != pName)
{
delete[] pName;
}
好多次我們都會忘記釋放pNme,並且管理釋放這些不會再用到的指針將會是很大的工程。可不可以指針自身進行管理?當然,智能指針就可以做到。我們實現一個智能指針,看看智能指針如何處理的更好。
下面寫一個實際例子,先寫一個叫做Person的類。
[cpp]
class Person
{
int age;
char* pName;
public:
Person(): pName(0),age(0)
{
}
Person(char* pName, int age): pName(pName), age(age)
{
}
~Person()
{
}
void Display()
{
printf("Name = %s Age = %d \n", pName, age);
}
void Shout()
{
printf("Ooooooooooooooooo");
}
};
class Person
{
int age;
char* pName;
public:
Person(): pName(0),age(0)
{
}
Person(char* pName, int age): pName(pName), age(age)
{
}
~Person()
{
}
void Display()
{
printf("Name = %s Age = %d \n", pName, age);
}
void Shout()
{
printf("Ooooooooooooooooo");
}
};
下面是客戶端代碼使用Person類。
[cpp]
void main()
{
Person* pPerson = new Person("Scott", 25);
pPerson->Display();
delete pPerson;
}
void main()
{
Person* pPerson = new Person("Scott", 25);
pPerson->Display();
delete pPerson;
}
現在我們來看這段代碼,每當我創建一個指針,都要管理釋放它。我要自動的釋放它,智能指針可以。因此我們創建一個SP類來管理Person的對象,客戶端的代碼可以這樣寫:
[cpp]
void main()
{
SP p(new Person("Scott", 25));
p->Display();
// Dont need to delete Person pointer..
}
void main()
{
SP p(new Person("Scott", 25));
p->Display();
// Dont need to delete Person pointer..
}
[cpp]
void main()
{
SP p(new Person("Scott", 25));
p->Display();
// Dont need to delete Person pointer..
}
void main()
{
SP p(new Person("Scott", 25));
p->Display();
// Dont need to delete Person pointer..
}
注意:
1,我們創建了一個SP對象來管理Person的指針,當SP對象的作用域結束,會自動析構,它將釋放Person的指針。
2,我們可以使用SP的對象p調用Display()函數,就像Person類的對象指針調用Display()函數,它的行為表現的像Person類的對象指針。
智能指針接口
智能指針表現出指針的行為,所以應該支持如下運算符:
Dereferencing (operator *)
Indirection (operator ->)
下面實現智能指針SP:
[cpp]
class SP
{
private:
Person* pData; // pointer to person class
public:
SP(Person* pValue) : pData(pValue)
{
}
~SP()
{
// pointer no longer requried
delete pData;
}
Person& operator* ()
{
return *pData;
}
Person* operator-> ()
{
return pData;
}
};
class SP
{
private:
Person* pData; // pointer to person class
public:
SP(Person* pValue) : pData(pValue)
{
}
~SP()
{
// pointer no longer requried
delete pData;
}
Person& operator* ()
{
return *pData;
}
Person* operator-> ()
{
return pData;
}
};
這就是我們智能指針,當它的析構函數被調用時會釋放Person類的對象指針。它也支持類似於指針的操作。
通用的智能指針
但是有個問題,我們智能控制Person類,也就是說每一種類型我們都要實現一個智能指針。我們可以使用模版使它通用。
[cpp]
template < typename T > class SP
{
private:
T* pData; // Generic pointer to be stored
public:
SP(T* pValue) : pData(pValue)
{
}
~SP()
{
delete pData;
}
T& operator* ()
{
return *pData;
}
T* operator-> ()
{
return pData;
}
};
void main()
{
SP<Person> p(new Person("Scott", 25));
p->Display();
// Dont need to delete Person pointer..
}
template < typename T > class SP
{
private:
T* pData; // Generic pointer to be stored
public:
SP(T* pValue) : pData(pValue)
{
}
~SP()
{
delete pData;
}
T& operator* ()
{
return *pData;
}
T* operator-> ()
{
return pData;
}
};
void main()
{
SP<Person> p(new Person("Scott", 25));
p->Display();
// Dont need to delete Person pointer..
}
我們的智能指針這樣就真的智能了嗎?驗證下面的代碼:
[cpp]
void main()
{
SP<Person> p(new Person("Scott", 25));
p->Display();
{
SP<Person> q = p;
q->Display();
// Destructor of Q will be called here..
}
p->Display();
}
void main()
{
SP<Person> p(new Person("Scott", 25));
p->Display();
{
SP<Person> q = p;
q->Display();
// Destructor of Q will be called here..
}
p->Display();
}
這樣就會存在一個問題:p和q關聯到了Person類的相同對象指針,當q結束它的作用域時會釋放Person類的對象指針,我們用p調用Display()函數會因為垂懸指針而失敗。我們應該在不使用它的時候再釋放,智能指針中引入計數便可解決。
計數器。
下面實現一個計數器的類RC.
[cpp]
class RC
{
private:
int count; // Reference count
public:
void AddRef()
{
// Increment the reference count
count++;
}
int Release()
{
// Decrement the reference count and
// return the reference count.
return --count;
}
};
class RC
{
private:
int count; // Reference count
public:
void AddRef()
{
// Increment the reference count
count++;
}
int Release()
{
// Decrement the reference count and
// return the reference count.
return --count;
}
};
下面把計數器引入到我們的智能指針中:
[cpp]
template < typename T > class SP
{
private:
T* pData; // pointer
RC* reference; // Reference count
public:
SP() : pData(0), reference(0)
{
// Create a new reference
reference = new RC();
// Increment the reference count
reference->AddRef();
}
SP(T* pValue) : pData(pValue), reference(0)
{
// Create a new reference
reference = new RC();
// Increment the reference count
reference->AddRef();
}
SP(const SP<T>& sp) : pData(sp.pData), reference(sp.reference)
{
// Copy constructor
// Copy the data and reference pointer
// and increment the reference count
reference->AddRef();
}
~SP()
{
// Destructor
// Decrement the reference count
// if reference become zero delete the data
if(reference->Release() == 0)
{
delete pData;
delete reference;
}
}
T& operator* ()
{
return *pData;
}
T* operator-> ()
{
return pData;
}
SP<T>& operator = (const SP<T>& sp)
{
// Assignment operator
if (this != &sp) // Avoid self assignment
{
// Decrement the old reference count
// if reference become zero delete the old data
if(reference->Release() == 0)
{
delete pData;
delete reference;
}
// Copy the data and reference pointer
// and increment the reference count
pData = sp.pData;
reference = sp.reference;
reference->AddRef();
}
return *this;
}
};
template < typename T > class SP
{
private:
T* pData; // pointer
RC* reference; // Reference count
public:
SP() : pData(0), reference(0)
{
// Create a new reference
reference = new RC();
// Increment the reference count
reference->AddRef();
}
SP(T* pValue) : pData(pValue), reference(0)
{
// Create a new reference
reference = new RC();
// Increment the reference count
reference->AddRef();
}
SP(const SP<T>& sp) : pData(sp.pData), reference(sp.reference)
{
// Copy constructor
// Copy the data and reference pointer
// and increment the reference count
reference->AddRef();
}
~SP()
{
// Destructor
// Decrement the reference count
// if reference become zero delete the data
if(reference->Release() == 0)
{
delete pData;
delete reference;
}
}
T& operator* ()
{
return *pData;
}
T* operator-> ()
{
return pData;
}
SP<T>& operator = (const SP<T>& sp)
{
// Assignment operator
if (this != &sp) // Avoid self assignment
{
// Decrement the old reference count
// if reference become zero delete the old data
if(reference->Release() == 0)
{
delete pData;
delete reference;
}
// Copy the data and reference pointer
// and increment the reference count
pData = sp.pData;
reference = sp.reference;
reference->AddRef();
}
return *this;
}
};
在看看客戶端的代碼:
[cpp]
Collapse | Copy Code
void main()
{
SP<PERSON> p(new Person("Scott", 25));
p->Display();
{
SP<PERSON> q = p;
q->Display();
// Destructor of q will be called here..
SP<PERSON> r;
r = p;
r->Display();
// Destructor of r will be called here..
}
p->Display();
// Destructor of p will be called here
// and person pointer will be deleted
}
Collapse | Copy Code
void main()
{
SP<PERSON> p(new Person("Scott", 25));
p->Display();
{
SP<PERSON> q = p;
q->Display();
// Destructor of q will be called here..
SP<PERSON> r;
r = p;
r->Display();
// Destructor of r will be called here..
}
p->Display();
// Destructor of p will be called here
// and person pointer will be deleted
}