1. 程式人生 > >C++11新特性之十:enable_shared_from_this

C++11新特性之十:enable_shared_from_this

 enable_shared_from_this是一個模板類,定義於標頭檔案<memory>,其原型為:

template< class T > class enable_shared_from_this;

       std::enable_shared_from_this 能讓一個物件(假設其名為 t ,且已被一個 std::shared_ptr 物件 pt 管理)安全地生成其他額外的 std::shared_ptr 例項(假設名為 pt1, pt2, ... ) ,它們與 pt 共享物件 t 的所有權。        若一個類 T 繼承 std::enable_shared_from_this<T> ,則會為該類 T 提供成員函式: shared_from_this 。 當 T 型別物件 t 被一個為名為 pt 的 std::shared_ptr<T> 類物件管理時,呼叫 T::shared_from_this 成員函式,將會返回一個新的 std::shared_ptr<T> 物件,它與 pt 共享 t 的所有權。

一.使用場合

       當類A被share_ptr管理,且在類A的成員函式裡需要把當前類物件作為引數傳給其他函式時,就需要傳遞一個指向自身的share_ptr。

1.為何不直接傳遞this指標

       使用智慧指標的初衷就是為了方便資源管理,如果在某些地方使用智慧指標,某些地方使用原始指標,很容易破壞智慧指標的語義,從而產生各種錯誤。

2.可以直接傳遞share_ptr<this>麼?

       答案是不能,因為這樣會造成2個非共享的share_ptr指向同一個物件,未增加引用計數導物件被析構兩次。例如:

  1. #include <memory>

  2. #include <iostream>

  3. class Bad

  4. {

  5. public:

  6. std::shared_ptr<Bad> getptr() {

  7. return std::shared_ptr<Bad>(this);

  8. }

  9. ~Bad() { std::cout << "Bad::~Bad() called" << std::endl; }

  10. };

  11. int main()

  12. {

  13. // 錯誤的示例,每個shared_ptr都認為自己是物件僅有的所有者

  14. std::shared_ptr<Bad> bp1(new Bad());

  15. std::shared_ptr<Bad> bp2 = bp1->getptr();

  16. // 列印bp1和bp2的引用計數

  17. std::cout << "bp1.use_count() = " << bp1.use_count() << std::endl;

  18. std::cout << "bp2.use_count() = " << bp2.use_count() << std::endl;

  19. } // Bad 物件將會被刪除兩次

輸出結果如下:

當然,一個物件被刪除兩次會導致崩潰。

正確的實現如下:

  1. #include <memory>

  2. #include <iostream>

  3. struct Good : std::enable_shared_from_this<Good> // 注意:繼承

  4. {

  5. public:

  6. std::shared_ptr<Good> getptr() {

  7. return shared_from_this();

  8. }

  9. ~Good() { std::cout << "Good::~Good() called" << std::endl; }

  10. };

  11. int main()

  12. {

  13. // 大括號用於限制作用域,這樣智慧指標就能在system("pause")之前析構

  14. {

  15. std::shared_ptr<Good> gp1(new Good());

  16. std::shared_ptr<Good> gp2 = gp1->getptr();

  17. // 列印gp1和gp2的引用計數

  18. std::cout << "gp1.use_count() = " << gp1.use_count() << std::endl;

  19. std::cout << "gp2.use_count() = " << gp2.use_count() << std::endl;

  20. }

  21. system("pause");

  22. }

輸出結果如下:

二.為何會出現這種使用場合

       因為在非同步呼叫中,存在一個保活機制,非同步函式執行的時間點我們是無法確定的,然而非同步函式可能會使用到非同步呼叫之前就存在的變數。為了保證該變數在非同步函式執期間一直有效,我們可以傳遞一個指向自身的share_ptr給非同步函式,這樣在非同步函式執行期間share_ptr所管理的物件就不會析構,所使用的變數也會一直有效了(保活)。

--------------------- 本文來自 燦哥哥 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/caoshangpa/article/details/79392878?utm_source=copy