我的结构的 shared_ptr 成员指向该结构的实例?

Posted

技术标签:

【中文标题】我的结构的 shared_ptr 成员指向该结构的实例?【英文标题】:A shared_ptr member of my struct pointing to an instance of the struct? 【发布时间】:2013-11-30 23:29:58 【问题描述】:

我是(增强)共享指针的新手,我正在尝试在代码中测试一些我不想为此目的自下而上重写的东西。

事实证明,当使用他们的 structs StructA 之一并让成员变量 shared_ptr<StructA> foo 指向 struct 对象的实例时,我可以非常优雅地解决我的问题。

这是简化的结构:

struct StructA 
  vars...
  funcs ...
  shared_ptr<StructA> foo;
;

这会导致 self-reset 错误的问题,所以我尝试撤消这个技巧,但它不起作用:

// <their code> (simplified)
StructA lp;
lp.SomePreparation(...);

for-loop () 

  lp.SetSomething(...);
  // my test
  lp.foo.reset(&lp);

  // <their large code section which I'd rather not touch...> 
  // which now works elegantly :)

  // A: doing nothing here, will result in self-reset assertation when 
  //    hitting the `reset(&lp)` above again in the loop. Detailed error below.
  lp.foo.reset(); // B: doing this here, results in glibc double free
  lp.foo.reset(new StructA()); // C: so does this

  // lp.foo = NULL; // what I'd do to a pointer in C.

没有调用 foo.reset():自复位错误

mybin: include/boost/smart_ptr/shared_ptr.hpp:397: void boost::shared_ptr<T>::reset(Y*) [with Y = StructA, T = StructA]: Assertion `p == 0 || p != px' failed.
Aborted

调用 foo.reset():

*** glibc detected *** mybin: double free or corruption (out): 0x00007fff974b3a30 ***
======= Backtrace: =========
/lib64/libc.so.6[0x342b6760e6]
/lib64/libc.so.6[0x342b678c13]
mybin(_ZN5boost14checked_deleteIN1214StructAEEEvPT_+0x26)[0xdd7dfd]
mybin(_ZN5boost6detail17sp_counted_impl_pIN1214LStructAEE7disposeEv+0x1c)[0xdd8b9a]
mybin(_ZN5boost6detail15sp_counted_base7releaseEv+0x42)[0xcedf54]
mybin(_ZN5boost6detail12shared_countD1Ev+0x27)[0xcee017]
mybin(_ZN5boost10shared_ptrIN1214StructAEED1Ev+0x1c)[0xd2dc38]
mybin(_ZN5boost10shared_ptrIN12C14StructAEE5resetEv+0x5b)[0x149b3a9]
....

【问题讨论】:

为什么你觉得自引用共享指针很优雅?你想做什么 因为这样我可以回收&lt;their large code ..部分的所有代码 但是共享指针在做什么呢?为什么需要它? 正常操作foo指向StructA的另一个对象。我发现我可以通过 foo 指向自己来滥用他们的代码。 【参考方案1】:

您正试图将共享指针指向自动变量的实例。这将导致调用delete 到不在“堆上”的内存。为此,您必须为自定义删除器(例如无操作删除器)提供模板参数。

StructA lp; // automatic variable
lp.SomePreparation(...);
...
lp.SetSomething(...);
// my test
lp.foo.reset(&lp); // This is your problem!
...
lp.foo.reset(); // (1)
lp.foo.reset(new StructA()); // (2)

(1)(2) 将尝试删除当前指向的对象。对于自动变量,这是一个问题,因为它会在超出范围时自动删除。

【讨论】:

是的,我知道这一点。这样的什么都不做删除器如何工作? ***.com/questions/12340810/… 什么都不做的删除器根本不会删除任何东西。 再次感谢。我明白了,我必须在共享指针的声明期间指定删除器。这会影响我不想更改的代码。目前,my answer 中的解决方法似乎更容易接受。【参考方案2】:

不确定您实际尝试实现什么,但您无法将局部变量的地址传递给 boost::shared_ptr。如果没有 shared_ptr 指向 boost::shared_ptr ,则 boost::shared_ptr 会销毁其包含的对象,并且 ofc 销毁基于堆栈的变量不是一个好主意。

你想完成什么?

【讨论】:

可以将局部变量的地址传递给结构中的共享指针,标记为&lt;their large code&gt;的例程都使用这个技巧(即访问foo )。我想说lp.foo = NULL; 删除对lp 的引用。 这没什么区别。重置时,您有效地创建了一个新的 shared_ptr 并且旧的将被销毁。其他人建议使用 null_deleter,如果传递 shared_ptr 会有所帮助,但您仍然可能最终进入 AV,因为包含的指针已经超出范围。【参考方案3】:

这似乎是个坏主意。一个可行但更不方便的解决方案是复制对象。

StructA lp;
lp.SomePreparation(...);
...
lp.SetSomething(...);
// my test
lp.foo.reset(new StructA());
lp.foo->var1 = lp.var1;
lp.foo->var2 = lp.var2; 


... more code

【讨论】:

以上是关于我的结构的 shared_ptr 成员指向该结构的实例?的主要内容,如果未能解决你的问题,请参考以下文章

类的 boost::shared_ptr 作为结构成员

使用指向 int 或 short int 的成员创建结构数组?

shared_ptr 到抽象基类(成员变量)是一个未声明的标识符[重复]

带有自定义删除器和分配器的 shared_ptr

程序在结构成员分配上停止而没有错误

结构体指针在使用完free后,该指针所指向的内存区域是啥,这个指针是变成了NULL,还是野指针。