C++智能指针:weak_ptr实现详解
文章目錄
- weak_ptr描述
- 聲明
- 作用
- 原理實現(xiàn)
- 函數(shù)成員使用
- 總結(jié)
weak_ptr描述
聲明
頭文件:<memory>
模版類:template <class T> class weak_ptr
聲明方式:std::weak_ptr<type_id> statement
作用
根據(jù)boost庫的官方描述,weak_ptr是由shared_ptr管理的一種弱引用對象的模版類。weak_ptr的對象能夠使用shared_ptr指針的構(gòu)造函數(shù)轉(zhuǎn)換為一個shared_ptr對象。但是這里shared_ptr的構(gòu)造函數(shù)參數(shù)需要包含weak_ptr的lock成員,該成員是weak_ptr用來獲取shared_ptr的指針。
這樣當(dāng)shared_ptr在多線程過程中被銷毀時shared_ptr::reset,weak_ptr的lock成員仍然能夠保留shared_ptr的成員,直到當(dāng)前shared_ptr正常終止,否則會出現(xiàn)非常危險的內(nèi)存泄漏。關(guān)于lock()成員的作用如下描述:
如下代碼
shared_ptr<int> p(new int(5));
weak_ptr<int> q(p);// some time laterif(int * r = q.get())
{// use *r
}
多線程環(huán)境中shared_ptr是可以被多個線程共享,在r被使用之前p對象執(zhí)行了p.reset(),正如我們上一篇文章中對shared_ptr的描述(C++智能指針:shared_ptr 實現(xiàn)詳解),reset成員會重置當(dāng)前shared_ptr指針的指向。此時,當(dāng)前線程如果繼續(xù)使用r指針,勢必會產(chǎn)生訪問空地址的異常問題
根據(jù)以上問題,使用weak_ptr::lock()成員來解決該問題
shared_ptr<int> p(new int(5));
weak_ptr<int> q(p);// some time later//使用weak_ptr的lock成員來獲取shared_ptr的指針
if(shared_ptr<int> r = q.lock())
{// use *r
}
關(guān)于lock()成員簡單說明一下,lock成員獲取到的shared_ptr p指針創(chuàng)建一個臨時對象(我們weak_ptr弱引用的體現(xiàn)),這個臨時對象同樣指向p,即使p執(zhí)了reset這樣的delete引用的操作,弱引用對象仍然持有改智能指針的地址,直到r指針的生命周期結(jié)束才會釋放。不得不佩服C++語言設(shè)計者的腦洞,為了保持C++對內(nèi)存操作的自由,即使耗費再大的精力也要實現(xiàn)這一目標(biāo),工匠精神才讓今天的C++越來越被底層程序員喜歡。
原理實現(xiàn)
源碼文件/boost/smart_ptr/weak_ptr.hpp
template<class T> class weak_ptr
{
private:// Borland 5.5.1 specific workaroundstypedef weak_ptr<T> this_type;
constructor構(gòu)造函數(shù)//默認(rèn)構(gòu)造函數(shù) weak_ptr() BOOST_NOEXCEPT : px(0), pn() // never throws in 1.30+ { }//拷貝構(gòu)造函數(shù) weak_ptr( weak_ptr const & r ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn ) { }destructor析構(gòu)函數(shù),這里weak_ptr使用的是默認(rèn)析構(gòu)函數(shù),一般使用expired返回空對象或者user_count()為0的情況則輔助shared_ptr釋放引用operator=1. weak_ptr & operator=( weak_ptr && r ) BOOST_NOEXCEPT {this_type( static_cast< weak_ptr && >( r ) ).swap( *this );return *this; }//2.這里會更加安全,使用lock成員獲取Y類型的指針 template<class Y> weak_ptr & operator=( weak_ptr<Y> const & r ) BOOST_NOEXCEPT {boost::detail::sp_assert_convertible< Y, T >();px = r.lock().get();pn = r.pn;return *this; }3. template<class Y> weak_ptr & operator=( shared_ptr<Y> const & r ) BOOST_NOEXCEPT {boost::detail::sp_assert_convertible< Y, T >();px = r.px;pn = r.pn;return *this; }weak_ptr::swap成員,交換兩個weak_ptr所指內(nèi)容以及地址void swap(this_type & other) BOOST_NOEXCEPT {//先交換地址,再交換內(nèi)容std::swap(px, other.px);pn.swap(other.pn); }weak_ptr::reset成員,·重新指定對象地址和內(nèi)容,就像是重新使用默認(rèn)構(gòu)造函數(shù)進(jìn)行了初始化void reset() BOOST_NOEXCEPT // never throws in 1.30+ {//使用默認(rèn)構(gòu)造函數(shù)構(gòu)造的對象和當(dāng)前對象進(jìn)行swap操作this_type().swap(*this); }weak_ptr::use_count成員,獲取shared_ptr對象被引用的次數(shù)。如果為空,則返回0long use_count() const BOOST_NOEXCEPT {return pn.use_count(); }weak_ptr::expired成員,當(dāng)根據(jù)use_count==0來返回bool,其返回為true的時候,使用lock獲取weak_ptr的指針只能獲取到空指針bool expired() const BOOST_NOEXCEPT {return pn.use_count() == 0; }weak_ptr::lock成員,會向weak_ptr對象返回一個shared_ptr。正如我們之前在weak_ptr作用中所描述的,防止多線程訪問時的shared_ptr內(nèi)存泄漏。此時weak_ptr對象獲取到的指針為臨時指針,會指向shared_ptr對象之前所指向的地址。shared_ptr<T> lock() const BOOST_NOEXCEPT {return shared_ptr<T>( *this, boost::detail::sp_nothrow_tag() ); }
函數(shù)成員使用
- 構(gòu)造函數(shù)
輸出如下:#include <iostream> #include <memory>struct C {int* data;};int main () {std::shared_ptr<int> sp (new int);std::weak_ptr<int> wp1;std::weak_ptr<int> wp2 (wp1);std::weak_ptr<int> wp3 (sp);std::cout << "use_count:\n";//weak_ptr對象如果為經(jīng)shared_ptr初始化,//它是沒有引用計數(shù)的,所以這里wp1和wp2引用計數(shù)都為0//只有wp3經(jīng)過了shared_ptr初始化,它的引用計數(shù)才為1std::cout << "wp1: " << wp1.use_count() << '\n';std::cout << "wp2: " << wp2.use_count() << '\n';std::cout << "wp3: " << wp3.use_count() << '\n';return 0; }use_count: wp1: 0 wp2: 0 wp3: 1 weak_ptr::operator=賦值運算符
輸出如下// weak_ptr::operator= example #include <iostream> #include <memory>int main () {std::shared_ptr<int> sp1,sp2;std::weak_ptr<int> wp;// sharing group:// --------------sp1 = std::make_shared<int> (10); // sp1wp = sp1; // sp1, wpsp2 = wp.lock(); // sp1, wp, sp2sp1.reset(); // wp, sp2//通過lock保留的臨時指針,重新獲取到了shared_ptr共享的地址sp1 = wp.lock(); // sp1, wp, sp2std::cout << "*sp1: " << *sp1 << '\n';std::cout << "*sp2: " << *sp2 << '\n';return 0; }*sp1: 10 *sp2: 10std::weak_ptr::swap交換指針地址以及對應(yīng)的內(nèi)容
輸出如下:#include <iostream> #include <memory>int main () {std::shared_ptr<int> sp1 (new int(10));std::shared_ptr<int> sp2 (new int(20));std::weak_ptr<int> wp1(sp1);std::weak_ptr<int> wp2(sp2);std::cout << "wp1 -> " << *wp1.lock() << " " << wp1.lock() << '\n';std::cout << "wp2 -> " << *wp2.lock() << " " << wp2.lock() << '\n';//這里的swap僅僅是交換wp2的各自的指向地址//并不會直接導(dǎo)致對應(yīng)智能指針原始指針的地址交換//根據(jù)輸出,所以很明顯,交換完成之后weak_ptr對象指向發(fā)生了變化,但是并未導(dǎo)致share_ptr指針的指向變化wp1.swap(wp2);std::cout << "sp1 -> " << *sp1 << " " << sp1 << '\n';std::cout << "sp2 -> " << *sp2 << " " << sp2 << '\n';std::cout << "wp1 -> " << *wp1.lock() << " " << wp1.lock() << '\n';std::cout << "wp2 -> " << *wp2.lock() << " " << wp2.lock() << '\n';return 0; }wp1 -> 10 0x11daf90 wp2 -> 20 0x11dafd0 sp1 -> 10 0x11daf90 sp2 -> 20 0x11dafd0 wp1 -> 20 0x11dafd0 wp2 -> 10 0x11daf90std::weak_ptr::reset成員,執(zhí)行之后weak_ptr對象就像是重新執(zhí)行了默認(rèn)構(gòu)造函數(shù),又變成了一個空的對象
輸出如下// weak_ptr::reset example #include <iostream> #include <memory>int main () {std::shared_ptr<int> sp (new int(10));std::weak_ptr<int> wp(sp);std::cout << "1. wp " << (wp.expired()?"is":"is not") << " expired\n";std::cout << "4. wp " << wp.use_count() << " *wp " << *wp.lock() << '\n';wp.reset();std::cout << "2. wp " << (wp.expired()?"is":"is not") << " expired\n";std::cout << "3. sp " << sp.use_count() << " *sp " << *sp << '\n';return 0; }1. wp is not expired 2. wp 2 *wp 10 3. wp is expired 4. sp 1 *sp 10
總結(jié)
shared_ptr和weak_ptr主要區(qū)別如下
- shared_ptr對象能夠初始化實際指向一個地址內(nèi)容而weak_ptr對象沒辦法直接初始化一個具體地址,它的對象需要由shared_ptr去初始化
- weak_ptr不會影響shared_ptr的引用計數(shù),因為它是一個弱引用,只是一個臨時引用指向shared_ptr。即使用shared_ptr對象初始化weak_ptr不會導(dǎo)致shared_ptr引用計數(shù)增加。依此特性可以解決shared_ptr的循環(huán)引用問題。
- weak_ptr沒有解引用*和獲取指針->運算符,它只能通過lock成員函數(shù)去獲取對應(yīng)的shared_ptr智能指針對象,從而獲取對應(yīng)的地址和內(nèi)容。
參考文檔:
http://www.cplusplus.com/reference/memory/weak_ptr/
https://www.boost.org/doc/libs/1_66_0/libs/smart_ptr/doc/html/smart_ptr.html#weak_ptr
總結(jié)
以上是生活随笔為你收集整理的C++智能指针:weak_ptr实现详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++智能指针: shared_ptr
- 下一篇: 大家感觉万圣节小炮的皮肤怎么样