在C ++ 11中使用shared_from_this()而不使用托管共享指针

时间:2015-12-10 22:43:58

标签: c++ pointers c++11 std shared-ptr

让我们说我有一个类,它是enable_shared_from_this的子类。这个基类的文档说在调用shared_from_this之前应该有一个共享指针拥有这个类。使用new分配类并调用shared_from_this来管理对象是否安全?

4 个答案:

答案 0 :(得分:3)

来自标准:

  

§20.8.2.4

     

shared_ptr shared_from_this();

     

shared_ptr shared_from_this()const;

     

7 *要求:enable_shared_from_t这应该是T的可访问基类。这应该是一个   类型为T的对象t的子对象。至少应有一个拥有& t的shared_ptr实例。

     

8返回:与p。

共享所有权的shared_ptr对象r      

9后置条件:r.get()== this

如果您在不受shared_from_this()管理的班级中致电shared_ptr,则结果将是未定义的行为,因为您尚未完成其中一个已记录的先决条件方法

我从经验中知道,在[当前版本] libc ++中,结果是抛出异常。但是,与所有未定义的行为一样,不能依赖它。

答案 1 :(得分:2)

  

这个基类的文档说在调用shared_from_this之前应该有一个拥有这个[object]的共享指针。

好的,很酷。

  

使用new分配[object]并调用shared_from_this来管理对象是否安全?

没有。在调用shared_from_this之前,应该有一个拥有此[object]的共享指针。

答案 2 :(得分:1)

不,这不安全。如果对象由shared_from_this管理,而不是通过shared_ptr分配(没有关联的new),则只应调用shared_ptr。例如这段代码

struct Test: std::enable_shared_from_this<Test> {
  std::shared_ptr<Test> getptr() {
    return shared_from_this();
  }
};

Test *test = new Test;
std::shared_ptr<Test> test2 = test->getptr();

将抛出std::bad_weak_ptr(至少在使用libstdc++时)。但这没关系:

std::shared_ptr<Test> test(new Test);
std::shared_ptr<Test> test2 = test->getptr();

答案 3 :(得分:1)

正如其他用户已经提到的,对不属于shared_from_this的实例的shared_ptr调用将导致未定义的行为(通常是异常,但没有保证)。

那么,为什么还有一个答案?

因为我曾经做过同样的问题并得到了几乎相同的答案,然后我开始挣扎于之后立即出现的另一个问题 - 我怎样才能保证所有实例都由{{1}管理}}

为了完整起见,我添加了另一个答案,并提供了有关这方面的一些细节 这是一个以前没有提到的简单解决方案。

确实如此简单的解决方案:私有构造函数工厂方法可变参数模板。 它遵循一个片段,在一个最小的例子中将所有这些片段混合在一起:

shared_ptr

基本的(琐碎的?)想法是禁止显式构造新实例,但是在这里使用名为#include<memory> #include<utility> class C: public std::enable_shared_from_this<C> { C() = default; C(const C &) = default; C(C &&) = default; C& operator=(const C &) = default; C& operator=(C &&c) = default; public: template<typename... Args> static std::shared_ptr<C> create(Args&&... args) noexcept { return std::shared_ptr<C>{new C{std::forward<Args>(args)...}}; } std::shared_ptr<C> ptr() noexcept { return shared_from_this(); } }; int main() { std::shared_ptr<C> c1 = C::create(); std::shared_ptr<C> c2 = C::create(*c1); std::shared_ptr<C> c3 = c2->ptr(); // these won't work anymore... // C c4{}; // std::shared_ptr<C> c5 = std::make_shared<C>(); // std::shared_ptr<C> c6{new C{}}; // C c7{*c1}; // ... and so on ... } 的工厂方法。
变量模板用于避免编写多种工厂方法,仅此而已。完美转发有助于我们以正确的方式做到这一点。

很简单,不是吗? 无论如何,我花了一段时间来弄清楚这一点,所以我希望这将有助于未来的读者遇到同样的疑问。