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

时间:2018-05-09 19:15:01

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

我正在尝试识别一个令人讨厌的错误,其中一个对象在进入地图时会自发地被破坏,经过几个小时的调试后,我想我可能还没有完全掌握 std ::的想法shared_ptr的

以下是上下文: 在方法内部,我声明了一个 std :: shared_ptr 并初始化它以指向当前对象的克隆(由 new 创建)。然后 - 在对对象进行一些修改之后 - 我在该指针上调用相同的方法(递归)。
在该方法的下一个递归中,决定将此对象插入 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,但我在那里用这个做的事情并没有影响原来的std :: shared_ptr。
为了验证这一点,我添加了代码,以便在插入地图时将额外的克隆添加到额外的std :: shared_ptr中,然后一切正常(只是更慢,并使用双倍)内存,这都是一个问题 - A类有很多复杂的数据。)

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

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

1 个答案:

答案 0 :(得分:2)

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

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

由于原始this,在此行中创建了一个完全独立的shared_ptr并且具有自己的独立引用计数。稍后在DoSomething()末尾的外部递归级别,原始shared_ptr pA超出范围,其引用计数降为0,对象被销毁,地图中的第二个shared_ptr开始悬挂。 / p>

解决方案1 ​​

您可以使用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()周围。这也解决了这个问题。