【C++之auto_ptr】
std::auto_ptr
std::auto_ptr 屬於 STL,當然在 namespace std 中,包含頭文件 #include<memory> 便可以使用。std::auto_ptr 能夠方便的管理單個堆內存對象。
我們從代碼開始分析:
void TestAutoPtr() {
std::auto_ptr<Simple> my_memory(new Simple(1)); // 創建對象,輸出:Simple:1
if (my_memory.get()) { // 判斷智能指針是否為空
my_memory->PrintSomething(); // 使用 operator-> 調用智能指針對象中的函數
my_memory.get()->info_extend = "Addition"; // 使用 get() 返回裸指針,然后給內部對象賦值
my_memory->PrintSomething(); // 再次打印,表明上述賦值成功
(*my_memory).info_extend += " other"; // 使用 operator* 返回智能指針內部對象,然后用“.”調用智能指針對象中的函數
my_memory->PrintSomething(); // 再次打印,表明上述賦值成功
}
} // my_memory 棧對象即將結束生命期,析構堆對象 Simple(1)
執行結果為:
Simple: 1
PrintSomething:
PrintSomething: Addition
PrintSomething: Addition other
~Simple: 1
上述為正常使用 std::auto_ptr 的代碼,一切似乎都良好,無論如何不用我們顯示使用該死的 delete 了。
其實好景不長,我們看看如下的另一個例子:
void TestAutoPtr2() {
std::auto_ptr<Simple> my_memory(new Simple(1));
if (my_memory.get()) {
std::auto_ptr<Simple> my_memory2; // 創建一個新的 my_memory2 對象
my_memory2 = my_memory; // 復制舊的 my_memory 給 my_memory2
my_memory2->PrintSomething(); // 輸出信息,復制成功
my_memory->PrintSomething(); // 崩潰
}
}
最終如上代碼導致崩潰,如上代碼時絕對符合 C++ 編程思想的,居然崩潰了,跟進 std::auto_ptr 的源碼后,我們看到,罪魁禍首是“my_memory2 = my_memory”,這行代碼,my_memory2 完全奪取了 my_memory 的內存管理所有權,導致 my_memory 懸空,最后使用時導致崩潰。
所以,使用 std::auto_ptr 時,絕對不能使用“operator=”操作符。作為一個庫,不允許用戶使用,確沒有明確拒絕[1],多少會覺得有點出乎預料。
看完 std::auto_ptr 好景不長的第一個例子后,讓我們再來看一個:
void TestAutoPtr3() {
std::auto_ptr<Simple> my_memory(new Simple(1));
if (my_memory.get()) {
my_memory.release();
}
}
執行結果為:
Simple: 1
看到什么異常了嗎?我們創建出來的對象沒有被析構,沒有輸出“~Simple: 1”,導致內存泄露。當我們不想讓 my_memory 繼續生存下去,我們調用 release() 函數釋放內存,結果卻導致內存泄露(在內存受限系統中,如果my_memory占用太多內存,我們會考慮在使用完成后,立刻歸還,而不是等到 my_memory 結束生命期后才歸還)。
正確的代碼應該為:
void TestAutoPtr3() {
std::auto_ptr<Simple> my_memory(new Simple(1));
if (my_memory.get()) {
Simple* temp_memory = my_memory.release();
delete temp_memory;
}
}
或
void TestAutoPtr3() {
std::auto_ptr<Simple> my_memory(new Simple(1));
if (my_memory.get()) {
my_memory.reset(); // 釋放 my_memory 內部管理的內存
}
}
原來 std::auto_ptr 的 release() 函數只是讓出內存所有權,這顯然也不符合 C++ 編程思想。
總結:std::auto_ptr 可用來管理單個對象的對內存,但是,請注意如下幾點:
(1) 盡量不要使用“operator=”。如果使用了,請不要再使用先前對象。
(2) 記住 release() 函數不會釋放對象,僅僅歸還所有權。
(3) std::auto_ptr 最好不要當成參數傳遞(讀者可以自行寫代碼確定為什么不能)。
(4) 由於 std::auto_ptr 的“operator=”問題,有其管理的對象不能放入 std::vector 等容器中。
(5) ……
使用一個 std::auto_ptr 的限制還真多,還不能用來管理堆內存數組,這應該是你目前在想的事情吧,我也覺得限制挺多的,哪天一個不小心,就導致問題了。
由於 std::auto_ptr 引發了諸多問題,一些設計並不是非常符合 C++ 編程思想,所以引發了下面 boost 的智能指針,boost 智能指針可以解決如上問題。