【问题标题】:Get a shared pointer from a dereferenced value of a shared pointer从共享指针的取消引用值中获取共享指针
【发布时间】:2017-09-23 18:15:06
【问题描述】:

想象有一个共享指针向量

typedef vector< shared_ptr< classA > > PointerVector;

还有一个 B 类,它还具有一个共享指针向量作为成员,以及一个在该向量中推回已取消引用的共享指针的方法。

ClassB
{
public:
    void add(classA &ref);
private:
    PointerVector vector;
}

假设 main 为 add 函数提供了一个取消引用的 shared_ptr 实例:

主要:

shared_ptr< classA > sharedptr ( new classA );
ClassA &ref = *sharedptr;
ClassB B;
B.add(ref);

有没有办法实现 add 函数来接受取消引用的共享指针并将其转换为初始共享指针?然后将其推回矩阵中?

这就是我想要做的:

void ClassB::add(classA &ref) {
    shared_ptr< classA > ptr = &ref;
    vector.push_back( ptr );
}

NOTE1: 当 classA 添加到向量中时,我希望共享指针计数增加一。我不需要创建另一个共享指针,我想“找到”对象之前拥有的共享指针。

注意2:我不能使用make_shared,因为我目前在tr1

【问题讨论】:

  • 你可以访问enable_shared_from_this吗?
  • @Revolver_Ocelot 我认为 enable_shared_from_this 包含在 tr1 中,是的
  • 那么它是正确的做事方式。使用它。

标签: c++ pointers memory shared-ptr


【解决方案1】:

通常你不能只“查找” 指向对象的指针,因为没有任何东西可以跟踪特定对象是否被指向。您应该自己设计这种机制,或者使用标准库提供的一种机制:enable_shared_from_this

第 1 步:从 std::enable_shared_from_this 派生您的类并提供一个成员函数来获取指针:

#include <memory>

struct ClassA: std::enable_shared_from_this<ClassA>
{
    std::shared_ptr<ClassA> get_pointer() 
    {
        return shared_from_this();
    }
    //...
};

第 2 步:确保您要获取指针的所有对象都由 shared_ptr 管理:

std::shared_ptr<ClassA> original_ptr(new ClassA);

第 3 步:只要您想获得指向对象的共享指针,就调用第 1 步中定义的函数:

void ClassB::add(classA& ref) {
    shared_ptr<classA> ptr = ref.get_pointer();
    vector.push_back( ptr );
}

【讨论】:

  • 此外,我会将ClassA 的构造函数设为私有,并添加一个返回shared_ptr&lt;ClassA&gt; 的静态工厂方法,以防止在为不受@ 管理的对象调用shared_from_this() 时出现未定义的行为987654331@.
【解决方案2】:

有一种方法可以做到这一点,但需要这样做可能意味着存在设计缺陷。

为什么它不起作用

shared_ptr 需要一个引用计数器才能工作。此计数器保存在创建第一个shared_ptr 时创建的控制块中。当您复制shared_ptr 时,该副本不仅复制指向托管对象的指针,还复制指向控制块的指针。这允许它访问引用计数器并在销毁对象时销毁块。

采用ClassA &amp; 的函数无权访问控制块。尝试创建一个新的shared_ptr 将创建一个引用计数为 1 的新控制块。当任一引用计数器达到 0 时,该对象将被销毁。因此,它会被销毁两次,这是未定义的行为。

它是如何工作的

正如 cmets 中已经提到的,std::enable_shared_from_this 解决了您的问题。你必须让你的类派生自它。

ClassA : std::enable_shared_from_this<ClassA> {...}

然后您可以调用ClassA.shared_from_this() 来获取shared_ptr,它是同一对象的现有shared_ptrs 的副本。

为什么我不推荐使用它

你必须非常小心enable_shared_from_this。 cppreference.com 状态

只允许在先前共享的对象上调用 shared_from_this,即在 std::shared_ptr 管理的对象上。否则行为未定义(C++17 前)std::bad_weak_ptr 被抛出(由默认构造的weak_this 中的shared_ptr 构造函数)(C++17 起)。

因此,在尝试使用shared_from_this 方法从中创建新的shared_ptr 之前,您必须确保该对象已被共享。

此外,您的函数签名接受ClassA&amp;。可以在堆栈上使用参数调用它;从堆栈对象创建shared_ptr 是危险的。如果您的函数需要共享所有权,它应该只接受shared_ptr&lt;ClassA&gt; 以便传达其意图。这使得它可以自我记录,并且更难在不牺牲任何东西的情况下处理不当。

【讨论】:

  • “所以你必须确保对象已经共享”“它可以在堆栈上使用参数调用” - 这可以通过将构造函数设为私有并添加静态工厂方法以返回 shared_ptr&lt;ClassA&gt;,即可轻松修复。
  • 这禁止在堆栈的任何位置创建ClassA 对象,即使是在不需要shared_ptrs 的程序部分。它也没有解决ClassB::adds 签名让调用者感到困惑的事实。我只是看不出有任何理由让add 不改变。
猜你喜欢
  • 2018-12-22
  • 1970-01-01
  • 1970-01-01
  • 2018-12-08
  • 1970-01-01
  • 2021-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多