C++標準程序庫提供的auto_ptr是一種智能型指針,幫助程序員防止「被異常拋出時發生資源泄漏」。注意我說的是「一種」智能型指針,現實生活中還有其餘許多有用的智能型指針,auto_ptr只是針對某個特定問題而設計的,對於其餘問題,auto-ptr無能爲力。ios
1、auto_ptr的設計動機:
函數的操做常常須要依如下模式進行:
一、獲取一些資源。
二、執行一些操做。
三、釋放所得到的資源。
假如函數一開始得到的資源被綁定在局部對象身上,當函數退出時,他們的析構函數被調用,從而自動釋放這些資源。可是若是函數一開始得到的資源是以顯式手法(好比說:new)得到,那就必須以顯示手法(好比說:delete)釋放。可是有時候會忘記delete或者異常一旦發生,函數馬上退出,根本執行不到函數尾端的delete語句,這就可能形成內存泄漏。固然你能夠在函數中實現捕捉全部異常。但會使得函數變得十分複雜且容易出錯。
若是使用智能型指針能保證在任何一種狀況下,只要本身被摧毀,就必定連帶釋放其所指的資源(由於智能型指針原本就是局部變量,因此不管是正常退出,仍是異常退出,都能保證該指針被銷燬從而釋放資源)。程序員
注意點:
一、auto_ptr是這樣一種指針:他是「他所指向的對象」的擁有者。因此,當身爲對象擁有者的auto_ptr被摧毀時,該對象也將遭到摧毀。auto_ptr要求一個對象只能有一個擁有者。再也不須要delete,也再也不須要catch。
二、auto_ptr擁有權是能夠轉移的:函數
std::auto_ptr<ClassA> ptr1(new ClassA); std::auto_ptr<ClassA> ptr2(ptr1); 或者 std::auto_ptr<ClassA> ptr1(new ClassA); std::auto_ptr<ClassA> ptr2; ptr2 = ptr1;
在第一個語句中,ptr1擁有了那個new出來的對象。在 第二個語句中,擁有權由ptr1轉交給ptr2。此後ptr2即擁有了那個new出來的對象,而ptr1不在擁有他。這樣,對象就只會被delete一次(在ptr2被摧毀時)。
若是ptr2在轉交擁有權以前擁有另外一個對象,則轉交操做執行以前會先調用delete,將ptr2所擁有的對象先摧毀。spa
std::auto_ptr<ClassA> ptr1(new ClassA); std::auto_ptr<ClassA> ptr2(new ClassA); ptr2 = ptr1; //ptr2以前擁有的對象被銷燬,ptr1將第一個new出來的對象的擁有權轉交給ptr2,ptr1爲NULL。
特殊用法:某個函數能夠利用auto_ptr將擁有權轉交給另外一個函數。這種狀況可能出如今兩種狀況:
a、auto_ptr被以傳值的方式被看成一個參數傳遞給某個函數。此時被調用函數的參數就得到了這個auto_ptr的擁有權。設計
void sink(std::auto_ptr<ClassA>);
b、當auto_ptr被看成返回值返回時,將擁有權轉交給調用端。指針
std::auto_ptr<ClassA> fun() { std::auto_ptr<ClassA> ptr(new ClassA); ... return ptr; } void gun() { std::auto_ptr<ClassA> ptr; for (int i=0; i<10; i++) { p = fun(); //一旦進入循環再次執行賦值動做,意味着ptr先前擁有的對象被銷燬了。 ... } }
三、const std::auto_ptr<class T> ptr;ptr的擁有權不容許被轉移。在這裏,關鍵詞const並不是意味着你不能更改auto_ptr所擁有的對象,而是意味着你不能更改auto_ptr的擁有權。例如:code
std::auto_ptr<int> f() { const auto_ptr<int> p(new int); auto_ptr<int> q(new int); *p = 42; //ok q = p; //error p = q; //error return p; //error }
四、並不存在針對array設計的auto_ptr。由於auto_ptr是透過delete而非delete[]來釋放其所擁有的對象。
五、auto_ptr不知足STL標準容器的對其元素的要求。由於在拷貝和賦值動做以後,本來的auto_ptr和新產生的auto_ptr並不相等。本來的auto_ptr會交出擁有權,而不是拷貝給新的auto_ptr。
六、auto_ptr不是引用計數型的指針——這種指針保證,若是有一組智能型指針指向同一個對象,那麼當且僅當最後一個智能型指針被註銷時,該對象纔會被摧毀。對象
運用實例:內存
#include <iostream> #include <memory> using namespace std; template <class T> ostream& operator<< (ostream& strm, const auto_ptr<T>& p) { if (NULL == p.get()) { strm << "NULL"; } else { strm << *p; } return strm; } int main() { auto_ptr<int> p(new int(42)); auto_ptr<int> q; cout << "after initialization:" << endl; cout << "p: " << p << endl; cout << "q: " << q << endl; q = p; cout << "after assigning auto pointers:" << endl; cout << "p: " << p << endl; cout << "q: " << q << endl; *q += 13; p = q; cout << "after change and reassignment:" << endl; cout << "p: " << p << endl; cout << "q: " << q << endl; return 0; }
注意:output操做符的第二個參數是一個const refernce,因此並無發生擁有權的轉移。
七、不能以通常指針的賦值手法來初始化一個auto_ptr:資源
std::auto_ptr<int> p(new int(42)); //OK std::auto_ptr<int> p = new int(24); //ERROR p = std::auto_ptr<int>(new int(24)); //OK p = new int(24); // ERROR
下面一個例子展現const auto_ptr的特性:
#include <iostream> #include <memory> using namespace std; template <class T> ostream& operator<< (ostream& strm, const auto_ptr<T>& p) { if (NULL == p.get()) { strm << "NULL"; } else { strm << *p; } return strm; } int main() { const auto_ptr<int> p(new int(42)); const auto_ptr<int> q(new int(0)); const auto_ptr<int> r; cout << "after initialization:" << endl; cout << "p: " << p << endl; cout << "q: " << q << endl; cout << "r: " << r << endl; *q = *p; //*r = *p; //ERROR:undefine behavior *p = -77; cout << "after assigning auto pointers:" << endl; cout << "p: " << p << endl; cout << "q: " << q << endl; cout << "r: " << r << endl; //q = p; //ERROR at compile time //r = p; //ERROR at compile time return 0; }
注意下列賦值操做是錯誤的: *r = *p; 這個句子對於一個「未指向任何對象」的auto_ptr進行提領操做。C++標準規定,這會致使未定義行爲,好比說致使程序的崩潰。