一、智能指針作爲一種內存管理技術主要爲了解決什麼問題?(屬於個人理解)
1、一般在應用軟件的開發過程中,應用程序的代碼執行基本上都是通過以下幾個步驟來完成:
(1)獲取資源(內存、文件句柄、數據庫連接等);
(2)執行功能代碼;
(3)釋放資源;
可能資源的獲取相對而言是一個比較容易處理的過程,以內存爲例,通過new操作符即可進行內存資源的獲得,但是在應用實現的過程中,可能程序員不能保證資源的正確釋放,甚至是忘記了調用delete或者是delete[]操作符,導致內存的泄露;有時候也是我們自己無法控制,譬如代碼在運行過程中產生異常,退出,那麼分配的資源也是無法釋放,針對以上種種情況,爲了解決資源的正確獲取和釋放,提出了智能指針來解決該種問題!
可能有時候會利用智能指針來保證線程安全等方面實踐!
二、智能指針利用到的技術思想是什麼?
(1)利用面嚮對象的技術,在一個obj的生存期結束的時候會自動調用自己的析構函數,實現內存的資源釋放
(2)利用GOF中的proxy(代理模式)的設計思想,利用一個obj來proxy指針的功能,實現和指針完全相同的操作(一般不包括指針的算術運算操作)
因此被稱爲智能指針,其實在實現層面上更本就不是一個“指針”(pointer),而是一個代理對象,重載了相關的->和*操作符,行爲上類似指針。
三、STL中的智能指針auto_ptr(釋放所有權的智能指針)
1、所在頭文件<memory>,內存管理
2、auto_ptr指針概述
auto_ptr是stl(c98標準)庫中的唯一一個標準智能指針,主要的目的就是避免相關資源泄露,保證代碼的異常安全。
特點是:auot_ptr代理的資源始終都只屬於唯一的一個auto_ptr,不能實現資源的共享,即使是在auto_ptr之間進行資源的傳遞也是如此,因此被稱爲“釋放所有權”。
正式這個特點也是它最主要的一個缺點,雖然可以對資源進行正確的管理,但是對應用人員的要求就比較高了,需要應用人員對這個智能指針的對象的特性比較瞭解,在使用的過程中,記住相關的特性,才能正確使用,避免出現一些“低級錯誤”代碼。
缺點:在實現上與常規的特性違背了,特別是對於copy construct和assign的操作,在理念上和我們的思想違背了,因爲它改變了被拷貝和被賦值者得屬性,因此在使用的時候我們必須要把握住它的這個特點,那麼纔可以正確的使用它。
使用的時候需要注意如下幾點:
(1)auto_ptr不能共享所有權
因此在使用auto_ptr的時候不能讓兩個auto_ptr同時擁有一個資源的指針,那麼就會出現資源的重複釋放,出現系統級的錯誤!在這裏需要提出一點:最好不要對auto_ptr進行“裸指針”的操作,即使用get()方法,因爲這樣很危險,代碼無法保證,只能由程序員自己去保證。
(2)不存在處理array的auto_ptr指針
因爲auto_ptr在析構的時候是使用delete,而不是delete[]
(3)auto_ptr不能滿足stl對元素的要求,這個應該是它的一個硬傷
因爲auto_ptr的所有權轉移的特點,使得它無法滿足container的要求在stl中爲了滿足功能性,在進行元素的操作都要求元素提供copy construct和assign,但是在容器中很多時候都是通過value拷貝的,很少有ref,並且參數大部分都是const ref,因此在對auto_ptr執行copy的時候,滿足c98的complier應該都會報錯,否則你就慘了。
(4)對於auto_ptr的使用,如果僅僅只是爲了保證資源的正確獲取和釋放
最好使用const auto_ptr obj,這樣在進行相互賦值的時候,complier會幫你檢查錯誤。const修飾的對象是obj,只是說自己的所有權是不允許被轉移,這屬於一種obj feature,因此obj proxy的pointer的value不能改變,但是*pointer的value是可以改變的。
(5)在auto_ptr中引入了auto_ptr_ref輔助類,主要是爲了解決const的變量作爲右值如何變爲左值的一個小技巧
大家應該都知道,對於一個函數如果返回一個obj對象,如果不是引用對象,那麼就會產生一個臨時變臉,在c++標準中對於零時變量,規定爲const的右值,但是如果把一個返回auto_ptr的零時變量的函數作爲右值,並且賦值給一個auto_ptr變量,例如:
auto_ptr a = function()< return auto_ptr(new int(11))>
因爲auto_ptr的copy construct的特性使得它無法使用const auto_ptr作爲入參,因此爲了解決這個問題,引入了上面的輔助類,在模板技術中重載了相關的類型轉換操作符,提供了auto_ptr_ref到auto_ptr的一個construct,這樣就通過這種技術實現了const auto_ptr的臨時變量到auto_ptr的對象值之間的“擁有權釋放”的問題。
對於相關技術可以參考stl中的源碼!
代碼示例說明:
#include <iostream>
#include <memory>
int main( void )
{
// 創建一個auto_ptr<int> 對象
std::auto_ptr<int> ptr( new int(11) );
// 通過重載*操作符實現value提取操作
if ( ptr.get() )
std::cout << *ptr << std::endl;
// 創建另一個對象,實現所有權的轉移
std::auto_ptr<int> cpptr = ptr;
// 判斷所有權是否轉移
if (ptr.get())
std::cout << "*ptr value = " << *ptr << std::endl;
if (cpptr.get())
std::cout << "*cpptr value = " << *cpptr << std::endl;
return 0;
};
輸出結果:可以看到ptr釋放了自己的所有權
在實現的過程中利用new操作符開闢了一個新的空間,但是沒有使用delete操作符,並不是忘記了
這個正是隻能指針的作用,可能通過內置類型無法看到效果,可以自己寫一個類,然後再析構函數中輸出相關的打印信息,就可以得到相關的驗證。
關於auto_ptr錯誤使用的一個例子:
#include <iostream>
#include <memory>
void function( std::auto_ptr<int> ptr )
{
std::cout << *ptr << std::endl;
}
int main( void )
{
// 創建一個auto_ptr<int> 對象
std::auto_ptr<int> ptr( new int(11) );
// 通過重載*操作符實現value提取操作
if ( ptr.get() )
std::cout << *ptr << std::endl;
function( ptr );
// 這個會報錯,因爲auto_ptr在使用的過程中進行了所有權的轉移
// 因此這個new的資源已經在function()函數中釋放了,ptr中擁有的
// 是一個空指針,這個會在運行時報錯,如果不報錯你就慘了!
// 應該該寫如下:
// if ( ptr.get() )
// *ptr = 20;
*ptr = 20;
return 0;
};
因此在這種情況下只能程序員自己去保證了,complier無法保證這種錯誤。
其實現在很少使用auto_ptr指針,而主要是使用boost庫中的五種智能指針!