enable_shared_from_this理解
enable_shared_from_this解析
???????enable_shared_from_this,是一個(gè)以其派生類為模板類型實(shí)參的基礎(chǔ)模板,繼承它,this指針就能變成shared_ptr。
什么時(shí)候該使用enable_shared_from_this模板類
???????在看下面的例子之前,簡單說下使用背景,單有一個(gè)類,某個(gè)函數(shù)需要返回當(dāng)前對象的指針,我們返回的是shared_ptr,為什么使用智能指針呢,這是因?yàn)?#xff1a;當(dāng)我們使用智能指針管理資源時(shí),必須統(tǒng)一使用智能指針,而不能再某些地方使用智能指針,某些地方使用原始指針,否則不能保持智能指針的語義,從而產(chǎn)生各種錯(cuò)誤。好了,介紹完背景,看下面的一段小程序:
??????
?????程序輸出:
?????
?????從上面的輸出你發(fā)現(xiàn)了什么,很明顯的發(fā)現(xiàn)只創(chuàng)建new了一個(gè)Test對象,但是卻調(diào)用了兩次析構(gòu)函數(shù),這對程序來說肯定是一個(gè)災(zāi)難。為什么會出現(xiàn)這種情況呢?main函數(shù)中的boost::shared_ptr<Test> p( new Test( ));將shared_ptr中引用計(jì)數(shù)器的值設(shè)置為1,而在GetObject函數(shù)中又通過boost::shared_ptr<Test> pTest(this);又將shared_ptr中的引用計(jì)數(shù)器的值增加了1,故在析構(gòu)時(shí)一個(gè)Test對象被析構(gòu)了兩次。即產(chǎn)生這個(gè)錯(cuò)誤的原因是通過同一個(gè)Test指針對象創(chuàng)建了多個(gè)shared_ptr,這是絕對禁止的。同時(shí)這也提醒我們在使用shared_ptr時(shí)一定不能通過同一個(gè)指針對象創(chuàng)建一個(gè)以上的shared_ptr對象。那么有什么方法從一個(gè)類的成員函數(shù)中獲取當(dāng)前對象的shared_ptr呢,其實(shí)方法很簡單:只需要該類繼承至enable_shared_from_this模板類,然后在需要shared_prt的地方調(diào)用enable_shared_from_this模板類的成員函數(shù)shared_from_this()即可,下面是改進(jìn)后的代碼:
??????
??????程序輸出:
??????
??????從輸出對象只被析構(gòu)了一次,這是我們想要的結(jié)果,因此enable_shared_from_this模板類的作用是:用來作為一個(gè)基類,它允許從一個(gè)成員函數(shù)中獲得一個(gè)當(dāng)前對象的shared_ptr。那么enable_shared_from_this模板類到底是如何工作的了?請看下文分解~
enable_shared_from_this模板類實(shí)現(xiàn)
??????打開enable_shared_from_this.hpp文件,會發(fā)現(xiàn)enable_shared_from_this模板類的實(shí)現(xiàn)如下:
??????
??????
?????從enable_shared_from_this模板類的實(shí)現(xiàn)文件中我們可以很容易的發(fā)現(xiàn)我們只能使用返回shared_ptr的shared_from_this()和返回shared_ptr的shared_from_this(),因?yàn)檫@兩個(gè)版本的shared_from_this()是public權(quán)限的,還有一個(gè)public權(quán)限的是internal_accept_owner函數(shù),但是注釋中已經(jīng)明顯指出不能調(diào)用這個(gè)函數(shù),這個(gè)函數(shù)會被shared_ptr自動調(diào)用,internal_accept_owner函數(shù)用來初始化enable_shared_from_this模板類中的唯一成員變量weak_ptr?weak_this。而shared_from_this()中是通過將weak_ptr?weak_this轉(zhuǎn)化成shared_ptr和shared_ptr來返回的,因此在使用shared_from_this()之前需要先初始化weak_ptr?weak_this對象,而weak_ptr?weak_this對象是在_internal_accept_owner函數(shù)中進(jìn)行的初始化,也就是說先需要?jiǎng)?chuàng)建shared_ptr對象。即在使用shared_from_this()函數(shù)之前,應(yīng)該先初始化對象的基類enable_shared_from_this,接著再初始化對象,最后初始化shared_ptr。正因?yàn)橛羞@個(gè)特點(diǎn)所以會出現(xiàn)以下常見的錯(cuò)誤:
使用enable_shared_from_this常見錯(cuò)誤
?????先來看情形1:
???????
??????這種用法明顯是錯(cuò)的,雖然對象的基類enable_shared_from_this類的構(gòu)造函數(shù)已經(jīng)被調(diào)用,但是shared_ptr的構(gòu)造函數(shù)并沒有被調(diào)用,因此weak_ptr?weak_this_并沒有被初始化,所以這時(shí)調(diào)用shared_from_this()是錯(cuò)誤的。
??????接著我們來看情形2:
??????
??????同樣這種做法也是錯(cuò)誤的,和情形1同樣的原因shared_ptr的構(gòu)造函數(shù)并沒有被調(diào)用,因此weak_ptr?weak_this_并沒有被初始化。
正確的做法應(yīng)該是:
???????
shared_ptr<Test> pTest( new Test() );這句話依次執(zhí)行的順序是:1 調(diào)用enable_shared_from_this的構(gòu)造函數(shù)。2 調(diào)用Test的構(gòu)造函數(shù)。 3 調(diào)用shared_ptr的構(gòu)造函數(shù)初始化weak_ptr?weak_this_。最后才能通過func()函數(shù)使用shared_from_this函數(shù)。
?????從上面的錯(cuò)誤中我們知道在使用enable_shared_from_this類中的shared_from_this()函數(shù)時(shí)應(yīng)該注意:
1. 不能在對象的構(gòu)造函數(shù)中使用shared_from_this()函數(shù)。
2. 先需要調(diào)用enable_shared_from_this類的構(gòu)造函數(shù),接著調(diào)用對象的構(gòu)造函數(shù),最后需要調(diào)用shared_ptr類的構(gòu)造函數(shù)初始化enable_shared_from_this的成員變量weak_this_。然后才能使用shared_from_this()函數(shù)。?
3. 如何程序中使用了智能指針shared_ptr,則程序中統(tǒng)一使用智能指針,不能使用原始指針,以免出現(xiàn)錯(cuò)誤。
**************************************************************************************************************
使用boost庫時(shí),經(jīng)常會看到如下的類
class A:public enable_share_from_this<A>
在什么情況下要使類A繼承enable_share_from_this?
使用場合:當(dāng)類A被share_ptr管理,且在類A的成員函數(shù)里需要把當(dāng)前類對象作為參數(shù)傳給其他函數(shù)時(shí),就需要傳遞一個(gè)指向自身的share_ptr。
我們就使類A繼承enable_share_from_this,然后通過其成員函數(shù)share_from_this()返回當(dāng)指向自身的share_ptr。
以上有2個(gè)疑惑:
1.把當(dāng)前類對象作為參數(shù)傳給其他函數(shù)時(shí),為什么要傳遞share_ptr呢?直接傳遞this指針不可以嗎?
一個(gè)裸指針傳遞給調(diào)用者,誰也不知道調(diào)用者會干什么?假如調(diào)用者delete了該對象,而share_tr此時(shí)還指向該對象。
2.這樣傳遞share_ptr可以嗎?share_ptr<this>
這樣會造成2個(gè)非共享的share_ptr指向一個(gè)對象,最后造成2次析構(gòu)該對象。
總結(jié)
以上是生活随笔為你收集整理的enable_shared_from_this理解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在析构函数中delete this指针问
- 下一篇: size_t和int区别