玩過C++shared_ptr類型的智能指針的同學,是否有接觸過std::enable_shared_from_this,它的出現為我們提供哪些編程方面的便利呢?下面就介紹它。
一、std::enable_shared_from_this的作用
按照enable_shared_from_this - C++ Reference (cplusplus.com)文檔介紹:繼承std::enable_shared_from_this的子類,可以使用shared_from_this成員函數獲取自身的shared_ptr指針;該類提供了允許繼承類的對象創建指向自身實例的shared_ptr,並且與存在shared_ptr對象共享所有權。什么意思呢?我們接下來通過代碼進行介紹。
二、如何使用std::enable_shared_from_this
上面已經介紹了,需要定義一個繼承類繼承這個類,代碼如下:
1 namespace test_enable_shared_from_this{ 2 3 class Derived : public std::enable_shared_from_this<Derived> 4 { 5 public: 6 void SetValue(int a) 7 { 8 _a = a; 9 } 10 int GetValue() const 11 { 12 return _a; 13 } 14 private: 15 int _a; 16 }; 17 18 }
那怎么使用這個繼承類呢?我們分別在棧,堆上創建對象,然后調用shared_from_this成員函數返回的對象是啥。
在棧上使用對象:
1 int main() 2 { 3 using namespace test_enable_shared_from_this; 4 Derived d; 5 auto obj = d.shared_from_this(); 6 7 return 0; 8 }
在棧上創建的對象不能調用該函數,會導致異常拋出:bad_weak_ptr。其實我們可以通過shared_from_this成員函數返回的是shared_ptr就知道不行,那么對象只能在堆上創建。能否裸指針呢?
1 int main() 2 { 3 using namespace test_enable_shared_from_this; 4 auto d = new Derived; 5 auto obj = d->shared_from_this(); 6 7 return 0; 8 }
直接在堆上創建對象也不行。我們只能使用智能指針std::shared_ptr和unique_ptr,其實大家應該早就知道是哪個了,這里做詳細說明是為了對問題的各種情況都進行驗證加深對其使用。接下來我們使用
std::shared_ptr。
1 int main() 2 { 3 using namespace test_enable_shared_from_this; 4 auto d = std::shared_ptr<Derived>(); 5 auto obj = d->shared_from_this(); 6 7 return 0; 8 }
觀察兩個對象,完全一模一樣。這就是文檔上介紹std::enable_shared_from_this提供的一種機制。那我們試試std::unique_ptr:
int main() { using namespace test_enable_shared_from_this; auto d = std::make_unique<Derived>(); auto obj = d->shared_from_this(); return 0; }
也不行。其實上面三種行不通的方式返回的指針都是空的。如下:
所以使用shared_from_this的繼承類對象只能是std::shared_ptr,其他方式都不行,如果誤用的話,會導致返回的對象為空而出現其他問題。
三、std::enable_shared_from_this的繼承問題
我們上面只是繼承一層,如果另外一個類繼承上面的類,那能夠正常使用shared_from_this函數嗎?獲取的對象是最后繼承的嗎?
如下代碼驗證:
1 namespace test_enable_shared_from_this{ 2 3 class Derived : public std::enable_shared_from_this<Derived> 4 { 5 public: 6 void SetValue(int a) 7 { 8 _a = a; 9 } 10 int GetValue() const 11 { 12 return _a; 13 } 14 private: 15 int _a; 16 }; 17 18 class Derived1 : public Derived 19 { 20 private: 21 int _b; 22 }; 23 24 }
調用代碼如下:
1 int main() 2 { 3 using namespace test_enable_shared_from_this; 4 auto d1 = std::make_shared<Derived1>(); 5 auto obj = d1->shared_from_this(); 6 7 return 0; 8 }
發現問題沒有?雖然d1和obj對象地址一樣,但是對象內存包含的成員屬性不同。d1有自身的屬性成員變量,但是obj沒有,只含有基類的屬性成員變量。是不是shared_from_this返回的對象中只包含那些直接繼承
std::enable_shared_from_this呢?我們用多繼承驗證下:
1 namespace test_enable_shared_from_this{ 2 3 class Derived : public std::enable_shared_from_this<Derived> 4 { 5 public: 6 void SetValue(int a) 7 { 8 _a = a; 9 } 10 int GetValue() const 11 { 12 return _a; 13 } 14 private: 15 int _a; 16 }; 17 18 class Derived1 : public std::enable_shared_from_this<Derived1> 19 { 20 private: 21 int _b; 22 }; 23 24 class Derived2 : public Derived, public Derived1 25 { 26 private: 27 int _c; 28 }; 29 30 }
1 int main() 2 { 3 using namespace test_enable_shared_from_this; 4 auto d2 = std::make_shared<Derived2>(); 5 auto obj = d2->shared_from_this(); 6 7 return 0; 8 }
直接提示執行不明確,這個很好理解,它不知道你究竟返回哪個子類std::shared_ptr。所以,繼承類中不能存在多次繼承std::enable_shared_from_this。哪個類繼承的這個類,就返回這個類實例化的對象。我一般在其他類對象需要共享該類對象的情況下使用,這樣該類就直接通過shared_ptr共享自身對象,如果其他類是通過引用或裸指針的方式共享該類,就不會繼承這個類。