【问题标题】:Calling a method of a *shared_ptr* - what happens to reference count?调用 *shared_ptr* 的方法 - 引用计数会发生什么?
【发布时间】:2018-05-09 19:15:01
【问题描述】:

我试图找出一个令人讨厌的错误,即对象在地图内时会自发损坏,经过几个小时的调试,我想我可能没有完全理解 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 的选择指针。

【问题讨论】:

  • 我不确定我是否完全理解你,但是std::enable_shared_from_this 你在找什么?
  • 您将this 插入到地图中,但是当拥有shared_ptr(在外部调用pA)消失时,thisshared_ptr(通过递归调用)拥有递归展开时超出范围,地图中的对象将被销毁。
  • 是的,@RichardCritten,但我如何让它保持活力?使用 shared_ptr 的全部原因是它保持活力。看起来我应该在这里废弃 shared-ptr 的东西,并在我删除它时使用我自己的逻辑。
  • 问题是为什么有一个 shared_ptr 呢?如果地图要拥有对象,要么将对象本身(按值)放入地图中,要么在地图中放入unique_ptr&lt;A&gt;
  • 我学会了更喜欢共享和唯一的ptr而不是简单的新建和删除,建议避免出现问题。所以我试着学习使用它。不过,对于这个用例来说可能不是正确的。

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


【解决方案1】:

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

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

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

解决方案 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

从您显示的代码 sn-ps 中,我发现您完全需要 shared_ptr 是非常值得怀疑的。您显示的任何内容都没有表明共享所有权。如果确实如此,请切换到unique_ptrs 和std::move() 他们周围。这也解决了问题。

【讨论】:

    猜你喜欢
    • 2016-11-05
    • 2022-06-17
    • 2014-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多