c++ - 调用 *shared_ptr* 的方法 - 引用计数会发生什么变化?

标签 c++ recursion shared-ptr c++17

我正在尝试识别一个讨厌的错误,在该错误中,对象在 map 内部时自发损坏,经过几个小时的调试,我想我可能没有完全理解 std::shared_ptr

这是上下文: 在一个方法中,我声明了一个 std::shared_ptr 并将其初始化为指向当前对象的克隆(由 new 创建)。然后 - 在对该对象进行一些修改之后 - 我对该指针调用了 same 方法(递归)。
在该方法的下一个递归中,决定将此对象插入 std::unordered_map(这是一个类属性,因此它在所有递归级别上都可用)。
这是一些伪代码来说明我的意思:

class A
{
  ...
  void DoSomething(void); // the recursive function
  A* Clone(void) const { return new A(this); }  // the clone method
  ...
  static std::unordered_map<std::shared_ptr<A>,int> myMap{};
};

void A::DoSomething(void)
{
  ...
  if (condition) myMap.insert({this,5});  // in a deeper recursive call, condition is true
  ...
  std::shared_ptr<A> pA(Clone());   // make a copy
  pA->...  // modify it 
  pA->DoSomething();  // here is the recursive call
  ...
}

问题: 有时,std::unordered_map 中指针后面的对象被销毁,并且当原始 std::shared_ptr 超出范围时,似乎会发生这种情况。

我(暂定)的理解:调用 std::shared_ptr 指向的对象的方法不会增加引用计数 - 在被调用的方法中,我有访问 this,这是 std::shared_ptr 指向的 ptr,但我在其中对 this 所做的操作不会影响原始 std::shared_ptr。
为了验证这一点,我添加了代码,将 extra 克隆到一个额外的 std::shared_ptr 中,就在插入映射的那一刻,然后一切正常(只是速度较慢,并且使用双倍内存,这都是一个问题 - A 类有很多复杂的数据)。

问题:我的理解是否正确?如果不是,我如何调用 std::shared_ptr 的方法,以便方法中的 this 仍然是“std::shared_ptr”? 或者这是不可能的,我必须使用其他设计?

关于重复:Should we pass a shared_ptr by reference or by value?似乎指向那个方向,但是关于按值或按引用传递参数,这不是我对 this 指针的选择。

最佳答案

你的理解基本正确。这一行是你的问题:

if (condition) myMap.insert({this,5});

因为原始的 this 一个完全独立的 shared_ptr 有它自己独立的引用计数被创建在这一行。稍后在 DoSomething() 末尾的外部递归级别中,原始 shared_ptr pA 超出范围,其引用计数降至 0,对象被销毁,第二个 shared_ptr map 中开始晃动。

解决方案一

你可以用std::enable_shared_from_this来解决:

class A : public std::enable_shared_from_this<A> { ... }

// Btw: Lose the void pseudo-parameter. This is not C. ;)
void A::DoSomething()
{
    if (condition) {
        myMap.insert({shared_from_this(), 5});
    }
}

潜在解决方案 2

从您展示的代码片段中,我发现您根本不需要 shared_ptr 是非常值得怀疑的。您显示的任何内容均不表示共享所有权。如果情况确实如此,请切换到 unique_ptrstd::move() 它们。这也解决了这个问题。

关于c++ - 调用 *shared_ptr* 的方法 - 引用计数会发生什么变化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50260555/

相关文章:

c++ - 使变量不可复制的紧凑方法

c++ - 如何将可变成员函数绑定(bind)到仿函数?

c++ - 由 gpu::dft 在 C++ 中使用 OpenCV 执行的缩放

python - Boost.Python boost::shared_ptr 没有通过值转换器找到 python

C++ 对象上的共享指针多次调用析构函数

c++ - 如何使用 google test for C++ 运行数据组合

java - 树打印树方法

python - 将任意长度的字典项展平为 Python 中的路径列表

haskell - 使用 Either 中断递归

c++ - enable_shared_from_this 和 make_shared 是否提供相同的优化