C++——智慧指標
你可能經常性的幹如下的事情。
void remodel(std::string & str)
{
std::string *ps = new std::string(str);
str = ps;
return;
}
其實你也不願意會發生上述事情,一般來說,程式設計師寫的是介面,外部呼叫該函式的時候,久而久之會發現記憶體水漲船高,歸根結底就是記憶體洩露導致的。
雖然你可以每次很注意要delete,但是保不齊你不需要立即釋放,或者也會遺漏忘記,甚至你不知道什麼時候釋放。然道沒有一種方法能幫你跳出這種“處境”嗎?
本文所有說得就是運用c++標準庫提供的智慧指標。簡單來說,
智慧指標(智慧指標模板類)是行為類似於指標的類物件。用於幫助管理動態記憶體分配的智慧指標模板。
雖然有解構函式的存在,也只能解決類物件的釋放。始終不能解決指標的釋放。
C++98提供了auto_ptr(C++11已將其摒棄),C++11提供了另外兩種解決方案,unique_ptr, shared_ptr。
使用方法如下:
#include <iostream> #include <memory> #include <string> using namespace std; class Report { private: string str; public: Report(const string s) :str(s) { cout << "Object Created!" << endl; } ~Report() { cout << "Object Deleted" << endl; } void comment() const { cout << str << endl; } }; void main() { { auto_ptr<Report> ps(new Report("using auto_ptr")); ps->comment(); } { shared_ptr<Report> ps(new Report("using shared_ptr")); ps->comment(); } { unique_ptr<Report> ps(new Report("using unique_ptr")); ps->comment(); } system("pause"); return; }
所有智慧指標都有explicit建構函式,只能顯示呼叫。
shared_ptr<double> pd;
double *p_reg = new double;
pd = p_reg; //不允許
pd = shared_ptr<double>(new double); //允許
shared_ptr<double> pshared = p_reg; // 不允許
shared_ptr<double> pshared(p_reg); //允許
一、為什麼C++11要摒棄auto_ptr:
void main() { /*auto_ptr<string> ps(new string("hello")); auto_ptr<string> vocation; ps = vocation;*/ auto_ptr<string> film[5] = { auto_ptr<string>(new string("1")), auto_ptr<string>(new string("2")), auto_ptr<string>(new string("3")), auto_ptr<string>(new string("4")), auto_ptr<string>(new string("5")) }; auto_ptr<string> pwin; pwin = film[2]; for (int i = 0; i < 5; i++) cout << *film[i] << endl; system("pause"); return; }
程式奔潰原因在於,程式將所有權從film[2]轉讓給pwin,導致film[2]不再引用該字串,當列印film[2]指向的字串時,發現這是一個空指標。
解決方法:把auto_ptr改成shared_ptr,
shared_ptr的原理是採用引用計數,當pwin和film[2]指向同一個物件時,引用計數從1增加到2,在程式末尾,後宣告的pwin先呼叫其解構函式,該解構函式將引用計數-1,變成了1,然後shared_ptr陣列成員釋放,將引用計數從1變成0,釋放以前分配的空間。
二、為何unique_ptr優於auto_ptr
如果出現下列語句
unique_ptr<string> ps3(new string("auto"));
unique_ptr<string> ps4;
ps3 = ps4; #編譯器認為該句非法
unique_ptr可防止p3和p4的解構函式釋放同一個物件。
但是如果像下列語句
unique_ptr<string> demo(const char * s)
{
unique_ptr<string> temp(new string(s));
return temp;
}
void main()
{
unique_ptr<string> ps;
ps = demo("Uniquely special");
}
demo函式返回一個臨時的unique_ptr,ps接管了temp的所有權(其實呼叫了unique_ptr的拷貝構造),因為demo生成的是右值
出了這語句temp就被銷燬。
總之,編譯器支援這種語法,如果源unique_ptr將存在一段時間,則編譯器禁止這樣做。
unique_ptr相比於auto_ptr還有另外一個優點,它有一個可用於陣列的變體。
模板auto_ptr支援new和delete但是不支援new[]和delete[],unique_ptr卻可以。
unique_ptr<double[]> pda(new double(5));
三、如何選擇智慧指標
如果程式要使用多個指向同一個物件的指標,應選擇shared_ptr,如果你的編譯器沒有提供,可以選擇boost庫中的shared_ptr
相反,可以是用unique_ptr,如果編譯器沒有提供,可以考慮使用boost庫中的scoped_ptr,它與unique_ptr類似。
最好不要用auto_ptr。