std::enable_shared_from_this使用
玩过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共享自身对象,如果其他类是通过引用或裸指针的方式共享该类,就不会继承这个类。