【问题标题】:std::set of shared_ptr's erasing leads to SIGABRTstd::set shared_ptr 的擦除导致 SIGABRT
【发布时间】:2018-07-18 23:22:18
【问题描述】:

我有std::set 指向某种类型的对象的共享指针(这里的ints 只是举例)。我需要的是插入由原始指针构造的共享 ptr。但是当我试图擦除一些 set 元素时(同样我只有一个原始指针),我应该构造 shared_ptr 并将其传递给擦除方法(在我看来这是真的,因为 shared_ptr 的比较运算符比较它们内部的原始指针)。

代码sn-p,导致SIGABRT:

std::set<std::shared_ptr<int>> sett;
int *rp = new int(5);
sett.emplace( rp );
sett.erase( std::shared_ptr<int>( rp ) );

【问题讨论】:

  • 你不能删除&amp;a
  • 你不能使用shared_ptr来管理指向栈对象的指针。
  • @liliscent 堆栈分配这里是例如。实际上使用 new 分配的内存会导致相同的行为
  • @Uroboros 你不能使用 2 shared_ptr 来管理 1 个原始指针。

标签: c++ c++11 pointers shared-ptr stdset


【解决方案1】:

这样不行:

sett.erase( shared_ptr<int>( rp ) );

这里,rp 是一个指针,所以你构造了一个匿名临时 shared_ptr,然后你删除它指向的值和内存,然后你的匿名临时再次删除它。

你不能构造两个不同的shared_ptrs 指向同一个对象。如果你需要这些方面的东西,你可以考虑enable_shared_from_this。或者更好的是,通过为std::set 实现一个允许与原始指针进行比较的比较函数,在根本不构造shared_ptr 的情况下从容器中擦除。有关更多信息,请参阅:What are transparent comparators?

【讨论】:

  • 谢谢,但我对You must not construct two different shared_ptrs pointing to the same object 感到困惑。它是共享的,而不是唯一的......
  • @Uroboros:如果两个指针相互了解,则共享。也就是说,如果 p1 指向某个对象,则 p2 可以从 p1 构造,但不能从对象的地址构造。他们无法简单地通过对象的地址进行协调(他们将在哪里存储他们的通信数据?),因此如果已经存在一个,则必须通过从第一个共享指针构造所有共享指针来“连接”它们。另一种思考方式:您通常不应该从原始指针构造共享指针——只能从new 表达式或通过make_shared
  • 想象一个老人快死了。周一,他让儿子安排他的葬礼。周二,他让女儿安排他的葬礼。如果儿子和女儿不沟通,就会有两场葬礼,一场以空棺异常失败。
【解决方案2】:

引用cppreference

使用拥有的原始底层指针构造一个新的 shared_ptr 由另一个 shared_ptr 导致未定义的行为。

当你这样做时:

sett.emplace( rp );

由于implicit type conversion,一个shared_ptr 被创建并被赋予了rp 指向的内存位置的所有权。我们称之为 sp1(1) 其中 (1) 表示引用计数

当你调用它时: sett.erase( std::shared_ptr&lt;int&gt;( rp ) );

以下事件发生:

  • 一个新的shared_ptr 拥有rp 指向的内存。 shared_ptr 认为内存的 ref-count 为 1。sp2(1)
  • erase 被调用。这会调用default comparator。这可能会导致删除第一个 shared_ptr sp1

  • sp1 调用析构函数,引用计数将变为 0。由于 ref-count 为 0,因此释放内存。

  • 当擦除返回时 sp2(1) 调用析构函数(因为它是为函数调用临时创建的)。 sp2

  • 管理的内存的引用计数变为 0
  • 析构函数不知道底层内存的命运已经被 sp1 的删除所密封,再次调用内存上的 delete。 Double delete disaster 在此时发生。

这就是为什么,要么在创建内存时将所有内容保留为 shared_ptr,要么为您的指针类型编写自定义比较器。

【讨论】:

    猜你喜欢
    • 2012-01-19
    • 2014-04-04
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多