C++ 调用*shared_ptr*方法-引用计数会发生什么变化?
我试图识别一个讨厌的bug,其中一个对象在地图中时会自动损坏,经过几个小时的调试,我想我可能还没有完全掌握std::shared_ptr的概念 以下是上下文: 在一个方法中,我声明了一个std::shared_ptr,并将其初始化为指向当前对象(由new创建)的克隆。然后,在对对象进行一些修改之后,我(递归地)调用该指针上的相同方法。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
在方法的下一个递归中,决定将此对象插入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 ptrpA
超出范围,其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 ptrpA
超出范围,其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,而不是简单的新建和删除,建议避免出现问题。因此我尝试学习使用它。但对于此用例来说,可能不是正确的做法。