【问题标题】:two shared_ptr from same enable_shared_from_this instance来自同一个 enable_shared_from_this 实例的两个 shared_ptr
【发布时间】:2018-04-25 17:10:20
【问题描述】:

鉴于这个类是 enable_shared_from_this

class connection : public std::enable_shared_from_this<connection>
{
   //...
};

假设我从connection* 创建两个std::shared_ptr 实例,如下所示:

std::shared_ptr<connection> rc(new connection);

std::shared_ptr<connection> fc(rc.get(), [](connection const * c) {
                                   std::cout << "fake delete" << std::endl;
                               });

到目前为止,它很好,因为资源 {connection*} 由 single shared_ptr — 准确地说是 rc 拥有,而 fc 只是有一个假删除器。

之后,我这样做:

auto sc = fc->shared_from_this();
//OR auto sc = rc->shared_from_this(); //does not make any difference!

现在shared_ptrrcfc — 将与sc 共享它的reference-count?换句话说,

std::cout << rc->use_count() << std::endl;
std::cout << fc->use_count() << std::endl;

这些应该打印什么?我测试了这段代码,foundrc 似乎有2 引用,而fc 只是1

我的问题是,为什么会这样? 正确的行为及其基本原理应该是什么?

我使用的是 C++11 和 GCC 4.7.3

【问题讨论】:

  • fcrc 一无所知,因为它是用原始指针构造的,就好像它是一个新对象一样。
  • @jtbandes - 一般来说。从enable_shared_from_this继承时,它可以知道更多。
  • 有趣!感谢您提供规范的链接 :)
  • 伪造的拥有智能指针(非拥有“拥有”智能指针)是非常有问题的。我可以看到它如何用于生命周期是永恒的对象(不限于带有 oa dtor 的静态对象),但总的来说,如果保留智能 ptr 的副本不延长生命周期对象“拥有”。
  • @curiousguy:嗯,“假”资源拥有智能ptr的想法在某些情况下可能很好。想象一个创建/销毁/管理对象的对象池,当客户端向它请求对象时,它通过将对象包装在 std::shared_ptr 中来提供,这样当 shared_ptr 超出范围时,它持有的对象返回到池(即变为可用再次使用).... [继续]。

标签: c++ shared-ptr reference-counting weak-ptr enable-shared-from-this


【解决方案1】:

原始指针重载假定拥有指向对象的所有权。因此,使用已由 shared_ptr 管理的对象(例如由 shared_ptr(ptr.get()) 管理的对象)使用原始指针重载构造 shared_ptr 可能会导致未定义的行为,即使该对象是派​​生自 std::enable_shared_from_this 的类型。 -- http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr

在您的情况下,您将获得具有两个不同所有权信息块但始终递增类的第一个共享指针实例的引用计数的共享指针。

如果您删除“假删除器”,您会遇到双重免费问题。

【讨论】:

    【解决方案2】:

    在 C++11 上(更一般地说,在 C++17 之前)

    我们唯一知道的是:

    [util.smartptr.enab] shared_from_this();:

    要求: enable_shared_from_this 应为 T 的可访问基类。*this 应为 T 类型对象 t 的子对象。应至少有一个 shared_ptr 实例 p 拥有&t.

    返回:与 p 共享所有权的 shared_ptr 对象 r。

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

    如果从字面上理解,暗示如果 fc->shared_from_this() 返回一个 rcfc 的副本是未指定的(尽管理智的实现将简单地分配给内部的 weak_ptr 一次,因此,正如您所观察到的,行为应该与 c++17 的情况相同)。


    从 C++17 开始

    情况很清楚:enable_shared_from_this 本质上是一个weak_ptr,由第一个看到它处于过期状态的shared_ptr 构造函数(或make_shared 工厂)分配。

    因此,rc 设置 weak_ptrfc 不设置,fc-&gt;shared_from_this() 返回 rc 的副本。 fc.get() 将在所有 rc 副本被销毁后立即返回一个僵尸指针。 您观察到的行为是正确的

    请注意,所有采用非空指针(最多为删除器和/或分配器)的 shared_ptr 构造函数将拥有该指针并管理其生命周期,就好像它是重新构造的一样,唯一的区别是只有第一个将分配给 enable_shared_from_this 的 weak_ptr,如果有的话。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-24
      • 2014-01-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多