您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“C++之智能指針初步及棄用auto_ptr的原因是什么”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
使用局部對象來管理資源的技術(shù)
delete后的指針變量就變成了一個失效指針(也叫作懸空指針)。
對于下面的代碼:
void Destroy(Object *op) { delete op; delete[] op; } Object *op = new Object(10); Object *arop = new Object[10]; Destroy(op); Destroy(arop);
因此:
智能指針是比原始指針更加智能的類,解決懸空指針多次刪除被指向?qū)ο?,以及資源泄漏問題,通常用來確保指針的壽命和其指向?qū)ο蟮膲勖恢隆?/p>
智能指針雖然很智能,很容易被誤用,智能也是有代價的。
auto_ptr
unqiue_ptr
(唯一性智能指針)
shared_ptr
(共享性智能指針)
weak_ptr
(管理弱引用)
其中后三個是C11支持,并且第一個已經(jīng)被C11棄用。
C98中的auto_ptr
所做的事情,就是動態(tài)分配對象以及當(dāng)對象不再需要時自動執(zhí)行清理。
下面我們首先來了解一下為什么要將auto_ptr移除的原因:
因為該類型的智能指針意義不明確,使用淺拷貝方式時,兩個對象擁有同一塊資源:我們模仿源碼的邏輯
了解一下:比如下面的代碼:
class Object { int value; public: Object(int x = 0):value(x){cout<<"Create Object:"<<this<<endl;} ~Object(){cout<<"Destroy Object:"<<this<<endl;} int & Value(){return value;} const int& Value() const{return value;} }; template<class _Ty> class my_auto_ptr { private: bool _Owns;//所有權(quán) _Ty* _Ptr; public: my_auto_ptr(_Ty* p = NULL):_Owns(p != NULL),_Ptr(p){} ~my_auto_ptr() { if(_Owns) { delete _Ptr; } _Owns = false; _Ptr = NULL; } _Ty* get() const { return _Ptr; } _Ty* operator->()const { return get(); } _Ty & operator*() { return *get(); } void reset(_Ty* p = NULL) { if(_Owns) { delete _Ptr; } _Ptr = p; } _Ty * release()const//編譯要通過,要么異變,要么強轉(zhuǎn)成普通指針 { _Ty* tmp = NULL; if(_Owns) { ((my_auto_ptr*)this)->_Owns = false; tmp = _Ptr; ((my_auto_ptr*)this)->_Ptr = NULL; } return tmp; } my_auto_ptr(const my_auto_ptr & op):_Owns(op._Owns) { if(_Owns) { _Ptr = op._Ptr; } } }; void fun() { my_auto_ptr<Object> pobj(new Object(10));//pobj是my_auto_ptr類型 cout<<pobj->Value()<<endl; cout<<(*pobj).Value()<<endl;//(*pobj)是Object的堆區(qū)對象。*(pobj._Ptr).Value() } int main() { my_auto_ptr<Object> pobja(new Object(10)); my_auto_ptr<Object> pobjb(pobja); }
相關(guān)函數(shù)解釋:
此時程序必然會導(dǎo)致程序崩潰引發(fā)異常,主函數(shù)結(jié)束時對同一部分資源釋放了兩次,堆內(nèi)存被釋放兩次
那么我們可能會考慮,將資源轉(zhuǎn)移,即修改拷貝構(gòu)造如下:利用是釋放函數(shù)
my_auto_ptr(const my_auto_ptr & op):_Owns(op._Owns),_Ptr(op.release()) {}
看似好像解決了上面的問題,實則存在隱患
繼續(xù)來看:下面的代碼存在什么問題呢?
void fun(my_auto_ptr<Object> apx) { int x = apx->Value(); cout<<x<<endl; } int main() { my_auto_ptr<Object> pobja(new Object(10)); fun(pobja); int a = pobja->Value(); cout<<a<<endl; }
上述代碼的執(zhí)行邏輯如下:
pobja
有兩個域擁有權(quán)域和指針域,拿pobja初始化形參apx時,會調(diào)動拷貝構(gòu)造函數(shù)
apx
將自己的擁有權(quán)域設(shè)為1,調(diào)動release函數(shù),銷毀了pobja對象的資源后,返回堆區(qū)對象的地址,apx接收后將自身的指針域指向原先pobja所指向的堆區(qū)對象
fun
函數(shù)結(jié)束,apx局部對象就會被析構(gòu),此時再打印a,對象其實已經(jīng)不存在了并且自身早已失去了pobja的擁有權(quán)。
綜上,此時智能指針的拷貝構(gòu)造函數(shù)的兩種寫法:
my_auto_ptr(const my_auto_ptr & op):_Owns(op._Owns) { if(_Owns) { _Ptr = op._Ptr; } } my_auto_ptr(const my_auto_ptr & op):_Owns(op._Owns),_Ptr(op.release()) {}
第一種存在的問題:Object的資源會被兩個釋放兩次
第二種存在的問題:解決了第一種問題,但是不能解決類似于實參對象初始化形參時,實參之前自身的資源丟失的問題,找不著了,因為這種情況太過于隱蔽,容易出錯,所以auto_ptr作為函數(shù)參數(shù)傳遞時一定要避免的?;蛟S你想到加上引用解決上面的問題,但是仔細(xì)思考后發(fā)現(xiàn),我們并不知道函數(shù)對傳入的傳入的auto_ptr做了什么,如果當(dāng)中的某些操作使其失去了對對象的所有權(quán),那么這還可能會導(dǎo)致致命的執(zhí)行期錯誤。獲取再加上const 才是個不錯的選擇。
因此,C11標(biāo)準(zhǔn)之前的auto_ptr
這個智能指針不被廣泛使用的原因就是:在某些應(yīng)用場景下,拷貝構(gòu)造函數(shù)的意義不明確,同理賦值語句也是這個道理,意義同樣不明確,因為C11標(biāo)準(zhǔn)之前并不存在移動賦值和移動構(gòu)造的概念,還有就是之前談到的一個對象和一組對象的問題,對于自定義類型而言,auto_ptr
的析構(gòu)函數(shù)僅能夠析構(gòu)一個對象,不能夠處理一組對象的情況,這些都是尚未解決的問題。
于是在C11中棄用,C17標(biāo)準(zhǔn)中直接移除。
歷史淵源:
在STL庫之前,有一個功能更加強大的boost庫,STL為了與其抗衡,應(yīng)急制造了STL,但制作的不夠完善,由此因為STL未解決auto_ptr
的問題,因此STl內(nèi)的容器vector和list都不想和auto_ptr建立聯(lián)系。
“C++之智能指針初步及棄用auto_ptr的原因是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。