从共享指针的取消引用值中获取共享指针

Get a shared pointer from a dereferenced value of a shared pointer

想象一下有一个共享指针向量

typedef vector< shared_ptr< classA > > PointerVector;

还有一个 Class 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 );
}

注意 1: 当将 classA 添加到 vector 时,我希望共享指针计数增加 1。我不需要创建另一个共享指针,我想 "find" 对象以前拥有的共享指针。

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

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

为什么它不起作用

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

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

它是如何工作的

如评论中所述,std::enable_shared_from_this 解决了您的问题。你必须让你的 class 从它派生。

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

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

为什么我不推荐使用它

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

It is permitted to call shared_from_this only on a previously shared object, i.e. on an object managed by std::shared_ptr. Otherwise the behavior is undefined (until C++17)std::bad_weak_ptr is thrown (by the shared_ptr constructor from a default-constructed weak_this) (since C++17).

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

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

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

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

#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 );
}