由一份auto_ptr原始碼所引發的思考 (轉)
由一份auto_ptr所引發的思考
Kyle
CPPCN 版權所有
如果我問你,auto_ptr最關鍵的地方,或者說它與一般指標最不一樣的地方在哪裡,你一定會說它是一個,它與自己所佔有的資源密切相關,當自己消亡的時候,它也會將自己所擁有的資源一同釋放。很好,它之所以會擁有這一特性,全都要歸於析構的功勞,在解構函式中,它會進行善後處理,這樣也就很好的避免了資源洩漏。當然,引入auto_ptr的原因還不至於這麼簡單,因為許多資源洩漏的問題主要是由於我們的粗心大意所致,所以只要我們細心一些,還是會避免一些不該發生的資源洩漏問題。那究竟是什麼原因讓我們引入auto_ptr呢?對了,你一定也想到了,就是在異常處理的時候。Ok,來看下面這個例子:
void foo()
{
ClassA *ptr=new ClassA;
try
{
/* 此處放置可能丟擲異常的操作 */
}
catch(…)
{
delete ptr;
throw;
}
delete ptr;
}
上面這個例子使用了一般的指標,你會發現它防止發生資源洩漏的處理是多麼複雜,必須在每個catch中進行資源的釋放,而且有可能會有許多的catch。天哪,這簡直就是災難,它會使我們的程式碼很長,不易維護,如果忘記其中的一個,就會產生莫名其妙的錯誤。既然一般的指標防止資源洩漏會如此的繁瑣,那有沒有一個辦法可以使我們不必操心資源的釋放呢,由於在異常發生的時候,會進行堆疊解退,所以我們不必擔心作為區域性變數的指標本身不被銷燬,既然這樣,我們乾脆建立一個指標物件,好比下面這樣:
template
class auto_ptr1
{
private:
T* ap;
public:
……..
~auto_ptr(); //資源釋放
}
當指標被銷燬的時候,必然會解構函式,那就在解構函式中進行資源的釋放不就ok了,呵呵,怎麼樣,是不是很簡單呢?的確,整個邏輯的確很簡單,但是如果我們在深入思考一下這個指標物件的特性的話,我們會發現有一個困難的問題等待我們去解決。那下面就讓我們來看看會遇到什麼困難。
由於在auto_ptr銷燬的時候它會自動透過解構函式釋放所擁有的資源,那麼也就決定了auto_ptr對於資源的獨佔性,即一個資源只能被一個auto_ptr所指向。這一點應該很好理解,假設有兩個auto_ptr指向同一個資源,那當其中一個被銷燬的時候,另一個將會指向哪裡呢?這種指標往往是最為危險的。既然這樣,我們怎樣才能保證這種獨佔性呢,其實也很簡單,當對指標進行賦值和複製的時候,剝奪原有指標對資源的擁有權,問題也就迎韌而解了。就好比這樣:
auto_ptr
auto_ptr
q=p; //p已經喪失了對資源的擁有權,q現在是p的主人
對於這種一般性的情況,問題似乎已經解決了,下面讓我們來看一種特殊但卻合理的情況:
auto_ptr class X X f() int main() X(Y a) template template explicit auto_ptr1(T* ptr=0) throw():ap(ptr){}
auto_ptr1(auto_ptr1& rhs) throw():ap(rhs.release()){}
template auto_ptr1& operator = (auto_ptr1& rhs) throw() template ~auto_ptr1() throw() T* get() const throw() T& operator *() const throw() T* operator ->() const throw() void reset(T* ptr=0) throw() auto_ptr1(auto_ptr_ref auto_ptr1& operator = (auto_ptr_ref template template 好了,今天就說到這吧,大家有什麼問題可以提出
{
auto_ptr
return p;
}
int main()
{
auto_ptr
return 0;
}
你認為上面這種情況怎麼樣,它是合理的,因為它實現了資源的順利移交,但是你認為auto_ptr
{
private:
int value;
public:
X(int v=0)
{
value=v;
}
X(X& a)
{
value=a.value;
a.value=0;
}
int set(int v)
{
value=v;
return value;
}
friend ostream& operator << (ostream& os, const X& x)
{
os<
};
{
X a(100);
return a;
}
{
X c(f());
cout<
}
上面這個例子和我們所遇到的情況有些相似X c(f());這一句是無法呼叫成功的,而且也不能把複製建構函式的引用引數變為const,因為我們要修改引數。Ok,我們就利用這個簡單的例子來解決我們所遇到的問題。既然我們已經想到的一些方案不能達到我們的目的,那我們怎麼做呢,對了,我們可以用型別轉換函式。下面讓我來幫你整理一下思路:
1.我們首先應該先定義一個型別轉換層,它的核心資料應該和X的核心資料一樣,例如:
struct Y
{
int val;
Y(int v):val(v){}
};
有了這個轉換層,我們就可以先把函式f()返回時所生成的臨時物件透過一個從X到Y的轉換函式轉型到Y。然後再透過一個從Y到X的轉換函式進行物件的構造。至此,所有問題都得以解決。下面讓我們來看一下具體方法。
2.新增一個從X到Y的型別轉換函式。如下:
operator Y()
{
Y y(value);
return y;
}
3.新增一個從Y到X的型別轉換函式,即只有一個引數的建構函式。
{
value=a.val;
}
OK,大功告成,你可以把這個例子在你的編譯器上實現,果然能夠解決所有的問題(在VC上會有一點問題,因為VC在臨時物件這一點上對標準C++的支援不夠好,用臨時物件作引數的時候不加const也可以編譯透過),下面我給出auto_ptr的一個實作範例,我想你應該能夠理解它了:)
struct auto_ptr_ref
{
Y* yp;
auto_ptr_ref(Y* rhs):yp(rhs){}
}; //注意這個轉換層
class auto_ptr1
{
private:
T* ap;
public:
typedef T element_type;
auto_ptr1(auto_ptr1
{
reset(rhs.release());
return *this;
}
auto_ptr1& operator = (auto_ptr1
{
reset(rhs.release());
return *this;
}
{
delete ap;
}
{
return ap;
}
{
return *ap;
}
{
return ap;
}
T* release() throw()
{
T* tmp(ap);
ap=0;
return tmp;
}
{
if(ap!=ptr)
{
delete ap;
ap=ptr;
}
}
{
reset(rhs.yp);
return *this;
}
operator auto_ptr_ref
{
return auto_ptr_ref
}
operator auto_ptr1
{
return auto_ptr1
}
};
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-993522/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 由吃飯引發的思考
- 由一個emoji引發的思考
- 由春節回家難引發的思考
- 由京東發貨引發的思考和分析
- ERP價格戰背後所引發的思考(轉)
- 由mv命令引發的對inode的思考
- 【高併發】由InterruptedException異常引發的思考Exception
- 由程式部署所引起的思考薦
- 由Siri和Alexa結婚引發的思考
- 由屎色自行車棚引發的思考
- 由sap一沖銷方法引發的思考
- 由整合ARouter引發的一些思考
- auto_ptr原始碼分析原始碼
- 由“自動播放”事件引發的幾點思考事件
- 由結構體對齊所引發的對C++類物件記憶體模型的思考(一)結構體C++物件記憶體模型
- 由結構體對齊所引發的對C++類物件記憶體模型的思考(二)結構體C++物件記憶體模型
- C#由轉換二進位制所引起的思考,瞭解下?C#
- 從Vue陣列響應化所引發的思考Vue陣列
- 一次線上問題排查所引發的思考
- 由“阿里巴巴入股星辰急便”引發的思考阿里
- 由Android 65K方法數限制引發的思考Android
- 由select for update鎖等待問題引發的深入思考
- 由 LG P4309 引發的擴充思考
- 一個由line-height引發的血案與思考
- 由《暗黑地牢》這款「地主模擬器」引發的思考
- 由ASP.NET Core讀取Response.Body引發的思考ASP.NET
- 由一把手槍引發的設計思考
- iOS開發基礎149-由UUIDString引發的思考iOSUI
- 由一把手槍的設計引發的思考
- 由script標籤引發了我對setTimeout非同步的思考非同步
- 由作業題引發對C++引用的一些思考C++
- JS學習筆記之由定時器引發的深入思考JS筆記定時器
- 一場由React引發的前後端分離架構的思考React後端架構
- for...in引發的思考
- 口碑割裂,內憂外患 由《最後生還者2》引發的思考
- 由Object.prototype.toString.call( )引發關於toString( )方法的思考Object
- 由重構react元件引發的函數語言程式設計的思考React元件函數程式設計
- 淺談雙人遊戲的設計與魅力——由《雙人成行》引發的思考遊戲