最近在補看《C++ Primer Plus》第6版,這的確是本好書,其中關于智能指針的章節解析的非常清晰,1解我之前的多處困惑。C++面試進程中,很多面試官都喜歡問智能指針相干的問題,比如你知道哪些智能指針?shared_ptr的設計原理是甚么?如果讓你自己設計1個智能指針,你如何完成?等等……。而且在看開源的C++項目時,也能隨處看到智能指針的影子。這說明智能指針不但是面試官愛問的題材,更是非常有實用價值。
下面是我在看智能指針時所做的筆記,希望能夠解決你對智能指針的1些困擾。
我們先來看1個簡單的例子:
void remodel(std::string & str)
{
std::string * ps = new std::string(str);
...
if (weird_thing())
throw exception();
str = *ps;
delete ps;
return;
}
當出現異常時(weird_thing()返回true),delete將不被履行,因此將致使內存泄漏。
如何避免這類問題?有人會說,這還不簡單,直接在throw exception();
之前加上delete ps;
不就好了。是的,你本應如此,問題是很多人都會忘記在適當的地方加上delete語句(連上述代碼中最后的那句delete語句也會有很多人忘記吧),如果你要對1個龐大的工程進行review,看是不是有這類潛伏的內存泄漏問題,那就是1場災害!
這時候我們會想:當remodel這樣的函數終止(不論是正常終止,還是由于出現了異常而終止),本地變量都將自動從棧內存中刪除―因此指針ps占據的內存將被釋放,如果ps指向的內存也被自動釋放,那該有多好啊。
我們知道析構函數有這個功能。如果ps有1個析構函數,該析構函數將在ps過期時自動釋放它指向的內存。但ps的問題在于,它只是1個常規指針,不是有析構凼數的類對象指針。如果它指向的是對象,則可以在對象過期時,讓它的析構函數刪除指向的內存。
這正是 auto_ptr、unique_ptr和shared_ptr這幾個智能指針背后的設計思想。我簡單的總結下就是:將基本類型指針封裝為類對象指針(這個類肯定是個模板,以適應不同基本類型的需求),并在析構函數里編寫delete語句刪除指針指向的內存空間。
因此,要轉換remodel()函數,應按下面3個步驟進行:
下面是使用auto_ptr修改該函數的結果:
# include <memory>
void remodel (std::string & str)
{
std::auto_ptr<std::string> ps (new std::string(str));
...
if (weird_thing ())
throw exception();
str = *ps;
// delete ps; NO LONGER NEEDED
return;
}
STL1共給我們提供了4種智能指針:auto_ptr、unique_ptr、shared_ptr和weak_ptr(本文章暫不討論)。
模板auto_ptr是C++98提供的解決方案,C+11已將將其摒棄,并提供了另外兩種解決方案。但是,雖然auto_ptr被摒棄,但它已使用了好多年:同時,如果您的編譯器不支持其他兩種解決力案,auto_ptr將是唯1的選擇。
使用注意點
templet<class T>
class auto_ptr {
explicit auto_ptr(X* p = 0) ;
...
};
因此不能自動將指針轉換為智能指針對象,必須顯式調用:
shared_ptr<double> pd;
double *p_reg = new double;
pd = p_reg; // not allowed (implicit conversion)
pd = shared_ptr<double>(p_reg); // allowed (explicit conversion)
shared_ptr<double> pshared = p_reg; // not allowed (implicit conversion)
shared_ptr<double> pshared(p_reg); // allowed (explicit conversion)
string vacation("I wandered lonely as a cloud.");
shared_ptr<string> pvac(&vacation); // No
使用舉例
#include <iostream>
#include <string>
#include <memory>
class report
{
private:
std::string str;
public:
report(const std::string s) : str(s) {
std::cout << "Object created.
";
}
~report() {
std::cout << "Object deleted.
";
}
void comment() const {
std::cout << str << "
";
}
};
int main() {
{
std::auto_ptr<report> ps(new report("using auto ptr"));
ps->comment();
}
{
std::shared_ptr<report> ps(new report("using shared ptr"));
ps->comment();
}
{
std::unique_ptr<report> ps(new report("using unique ptr"));
ps->comment();
}
return 0;
}
先來看下面的賦值語句:
auto_ptr< string> ps (new string ("I reigned lonely as a cloud.”);
auto_ptr<string> vocation;
vocaticn = ps;
上述賦值語句將完成甚么工作呢?如果ps和vocation是常規指針,則兩個指針將指向同1個string對象。這是不能接受的,由于程序將試圖刪除同1個對象兩次――1次是ps過期時,另外一次是vocation過期時。要避免這類問題,方法有多種:
上一篇 仿網易彩票代碼實現
下一篇 分享幾款html5游戲源代碼