《C++标准程序库》读书笔记(三)
?????STL中的智能指針auto_ptr可以實現簡單的內存自動回收,防止內存泄漏(memory leakage)。auto_ptr實際是一個類,在該類析構時自動調用delete,從而達到了內存回收的效果。但是,由于同一個指針同一時刻只能被一個auto_ptr占用,如果采用賦值操作(=)或者拷貝構造函數調用,就會發生所有權轉移,例如:
auto_ptr<int>?p(new?int(0));auto_ptr<int>?q;
此時,p擁有指向一個int的指針,q的指針為空。如果執行q=p;則,p指向空,q指向int;但是,這樣所有權轉換的問題同樣發生在參數傳遞中,例如
void?foo(auto_ptr<int>?t);如果調用 foo(p);那么p就丟失了指針,所以一個解決方法是用引用,例如:
void?foo1(auto_ptr<int>&?t);
void?foo2?(const?auto_ptr<int>&?t);
兩者都是可以的,不過foo1非常不安全,因為在函數里面很容易通過類似賦值的操作使t丟失指針,而foo2不會。例如
void?foo2(const?auto_ptr<int>&?t){?
?????auto_ptr<int>?m;?m=t;
}
會發生編譯錯誤,從而避免災難的發生。但隨之又出現一個很大的問題,就是auto_ptr類的拷貝構造函數,或者賦值函數。最理想的情況是這樣(如果能成功,就不會有別的什么問題):
auto_ptr(const?auto_ptr&?rhs):ap(rhs.release()){}但由于上述的原因,會發生編譯錯誤(因為調用了release(),而release()會改變成員變量,不再是const)。所以只能去掉const,變為
auto_ptr(auto_ptr&?rhs):ap(rhs.release()){}這樣可以編譯成功,而且往往也能正確運行,但是唯一的問題是: 當rhs為右值時會出現問題。
為了簡化問題,先假設拷貝構造函數什么都不做,即:
auto_ptr(auto_ptr& rhs){}
那么,如果有 auto_ptr<int> p(new int(10)),執行 auto_ptr<int> q(p),不會有任何問題,因為p是左值。但如果執行auto_ptr<int> q(auto_ptr<int>(new int(10))) ,則會發生編譯錯誤,因為auto_ptr<int>(new int(10)) 是右值,對右值的引用只能是常引用,也就是"const auto_ptr& rhs"的形式。但這里要注意的是,剛才那段代碼用VC編譯沒有任何問題,并且可以順利運行,但是用GCC之類的標準c++就不能順利編譯。
在VC中auto_ptr<int>& p=auto_ptr<int>(new int(0))? 是合法的,但在標準C++中是不合法的,只有const auto_ptr<int>& p=auto_ptr<int>(new int(0)) 才是合法的,也即在標準C++中,對右值的引用只能是常引用。所以說,要在標準C++中實現 auto_ptr<int> p(auto_ptr<int>(new int(0))) 就變得不可能了,因為如上所說,拷貝構造函數是這樣的形式:auto_ptr(auto_ptr<T>& rhs):ap(rhs.release()){}
但是不能把右值傳到一個非常引用中。但畢竟有聰明的人能想到解決辦法,利用代理類( proxy class)聲明如下結構,為了方便,我用int代替模板參
struct?auto_ptr_ref{
???int*?p;
???auto_ptr_ref(int?*t):p(t){}
};
然后在auto_ptr類中增加了以下函數
auto_ptr(auto_ptr_ref?rhs):ap(rhs.p){}auto_ptr&?operator=(auto_ptr_ref?rhs){reset(rhs.p);?return?*this;}
operator?auto_ptr_ref(){return?auto_ptr_ref(release());}
之后,如果在標準C++有以下調用(VC中也會按照這個步驟調用,雖然沒有auto_ptr_ref它也能直接調用)
auto_ptr<int> p(auto_ptr<int>(new int(0)))
便可以成功,過程如下:
1. 構造臨時對象 auto_ptr<int>(new int(0))
2. 想將臨時對象通過拷貝構造函數傳給p,卻發現沒有合適的拷貝構造函數,因為只有auto_ptr(auto_ptr& rhs)這個不能用,又沒有auto_ptr(const auto_ptr& rhs) (因為用了在所有權轉移中會出錯)!
3. 編譯器只能曲線救國,看看類型轉換后能不能傳遞。
4. 由于我們定義了 operator auto_ptr_ref() 所以編譯器自然就可以試一下轉為 auto_ptr_ref類型。
5. 編譯器猛然間發現,我們定義了 auto_ptr(auto_ptr_ref rhs):ap(rhs.p){} 的構造函數,可以傳遞。
6. 順利構造p,任務完成。
其實說白了問題很簡單,因為構造函數不能接受右值,則取中間左值=右值, 然后再讓函數接受中間左值。 而這一系列過程正是利用編譯器能夠自動進行類型轉換而完成的。
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的《C++标准程序库》读书笔记(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#WinForm App自动更新(Li
- 下一篇: J2me Canvas