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

C++ 调用*shared_ptr*方法-引用计数会发生什么变化?,c++,recursion,shared-ptr,c++17,C++,Recursion,Shared Ptr,C++17,我试图识别一个讨厌的bug,其中一个对象在地图中时会自动损坏,经过几个小时的调试,我想我可能还没有完全掌握std::shared_ptr的概念 以下是上下文: 在一个方法中,我声明了一个std::shared_ptr,并将其初始化为指向当前对象(由new创建)的克隆。然后,在对对象进行一些修改之后,我(递归地)调用该指针上的相同方法。 在方法的下一个递归中,决定将此对象插入std::unordered_映射(这是一个类属性,因此在所有递归级别上都可用)。 这是一些伪代码来说明我的意思: clas

我试图识别一个讨厌的bug,其中一个对象在地图中时会自动损坏,经过几个小时的调试,我想我可能还没有完全掌握std::shared_ptr的概念

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

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
  ...
}
A类
{
...
void DoSomething(void);//递归函数
A*Clone(void)const{返回新的A(this);}//克隆方法
...

静态标准::无序地图您的理解基本正确。这一行是您的问题:

if (condition) myMap.insert({this,5});
由于原始
在此行中创建了一个完全独立的
共享的\u ptr
,具有自己的独立引用计数。稍后在
DoSomething()末尾的外部递归级别中
原始共享\u ptr
pA
超出范围,其refcount降至0,对象被销毁,地图中的第二个共享\u ptr开始悬挂

解决方案1 您可以通过以下方法解决此问题:

class A:public std::从{…}启用{u共享}
//顺便说一句:丢失void伪参数。这不是C.;)
void A::DoSomething()
{
如果(条件){
insert({shared_from_this(),5});
}
}
潜在解决方案2
从您展示的代码片段中,我发现您是否需要
shared_ptr
非常值得怀疑。您展示的任何内容都不表示共享所有权。如果确实如此,请切换到
unique_ptr
s和
std::move()
把它们转过来。这也解决了问题。

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

if (condition) myMap.insert({this,5});
由于原始
在此行中创建了一个完全独立的
共享的\u ptr
,具有自己的独立引用计数。稍后在
DoSomething()末尾的外部递归级别中
原始共享\u ptr
pA
超出范围,其refcount降至0,对象被销毁,地图中的第二个共享\u ptr开始悬挂

解决方案1 您可以通过以下方法解决此问题:

class A:public std::从{…}启用{u共享}
//顺便说一句:丢失void伪参数。这不是C.;)
void A::DoSomething()
{
如果(条件){
insert({shared_from_this(),5});
}
}
潜在解决方案2
从您展示的代码片段中,我发现您是否需要
shared_ptr
非常值得怀疑。您展示的任何内容都不表示共享所有权。如果确实如此,请切换到
unique_ptr
s和
std::move()
他们周围。这也解决了问题。

我不确定我是否完全理解你,但你在寻找什么?你将
这个
插入地图,但是
这个
是属于
共享的\u ptr
(通过递归调用)的,当拥有
共享的\u ptr
(在外部调用
pA
)递归展开时超出范围映射中的对象将被销毁。是的,@RichardCritten,但我如何使其保持活动状态?使用shared_ptr的全部原因是它保持活动状态。看起来我应该在这里废弃共享ptr,并在删除它时使用我自己的逻辑。问题是为什么要使用共享_ptr?如果映射要拥有对象,请将对象本身放入(按值)在地图中或在地图中放置一个
唯一的\u ptr
我学会了更喜欢共享和唯一的ptr而不是简单的新建和删除,建议避免出现问题。因此我尝试学习使用它。但对于这个用例来说,可能不是正确的做法。我不确定我是否完全理解您,但您正在寻找的是什么?您将
插入到地图,但当拥有的
共享的ptr
(在外部调用
pA
中)时,该
属于
共享的ptr
(通过递归调用)递归展开时超出范围映射中的对象将被销毁。是的,@RichardCritten,但我如何使其保持活动状态?使用shared_ptr的全部原因是它保持活动状态。看起来我应该在这里废弃共享ptr,并在删除它时使用我自己的逻辑。问题是为什么要使用共享_ptr?如果映射s要拥有该对象,请将对象本身(按值)放入地图或在地图中放入
唯一的\u ptr
。我已学会了更喜欢共享和唯一的ptr,而不是简单的新建和删除,建议避免出现问题。因此我尝试学习使用它。但对于此用例来说,可能不是正确的做法。