std::set 次 shared_ptr 次擦除导致 SIGABRT
std::set of shared_ptr's erasing leads to SIGABRT
我有 std::set
个指向某种类型对象的共享指针(这里的 int
只是为了举例)。我需要的是插入由原始指针构造的共享指针。但是当我试图擦除一些集合元素时(同样我只有一个原始指针),我应该构造 shared_ptr
并将它传递给擦除方法(在我看来这是真的,因为 shared_ptr
的比较运算符在 ) .
中比较它们的原始指针
代码片段,导致 SIGABRT:
std::set<std::shared_ptr<int>> sett;
int *rp = new int(5);
sett.emplace( rp );
sett.erase( std::shared_ptr<int>( rp ) );
这不行:
sett.erase( shared_ptr<int>( rp ) );
这里,rp
是一个指针,所以你构造一个匿名临时shared_ptr
,然后你删除它指向的值和内存,然后你的匿名临时再删除它。
您不得构造两个指向同一对象的不同 shared_ptr
。如果您需要这些方面的东西,您可以考虑 enable_shared_from_this
。或者更好的是,通过为 std::set
实现允许与原始指针进行比较的比较函数,从容器中擦除而根本不构造 shared_ptr
。有关更多信息,请参阅:What are transparent comparators?
引用自cppreference
Constructing a new shared_ptr using the raw underlying pointer owned
by another shared_ptr leads to undefined behavior.
当您这样做时:
sett.emplace( rp );
由于 implicit type conversion 创建了 shared_ptr
并赋予了 rp
指向的内存位置的所有权。让我们称之为 sp1(1) 其中 (1) 表示引用计数
当你这样调用时:
sett.erase( std::shared_ptr<int>( rp ) );
发生以下事件序列:
- 一个新的
shared_ptr
拥有 rp
指向的内存。 shared_ptr
认为内存的引用计数为1。sp2(1)
erase
被调用。这将调用 default comparator。这可能会导致删除第一个 shared_ptr sp1。
为 sp1 调用析构函数,引用计数将变为 0。由于引用计数为 0,因此内存被释放。
When erase returns sp2(1) 析构函数被调用(因为这是为函数调用临时创建的)。对于由 sp2
管理的内存,引用计数变为 0
析构函数不知道底层内存的命运已经被删除 sp1 再次调用内存上的 delete。 Double delete disaster 发生在此时。
这就是为什么,要么从创建内存时就shared_ptr
保留所有内容,要么为您的指针类型编写自定义比较器。
我有 std::set
个指向某种类型对象的共享指针(这里的 int
只是为了举例)。我需要的是插入由原始指针构造的共享指针。但是当我试图擦除一些集合元素时(同样我只有一个原始指针),我应该构造 shared_ptr
并将它传递给擦除方法(在我看来这是真的,因为 shared_ptr
的比较运算符在 ) .
代码片段,导致 SIGABRT:
std::set<std::shared_ptr<int>> sett;
int *rp = new int(5);
sett.emplace( rp );
sett.erase( std::shared_ptr<int>( rp ) );
这不行:
sett.erase( shared_ptr<int>( rp ) );
这里,rp
是一个指针,所以你构造一个匿名临时shared_ptr
,然后你删除它指向的值和内存,然后你的匿名临时再删除它。
您不得构造两个指向同一对象的不同 shared_ptr
。如果您需要这些方面的东西,您可以考虑 enable_shared_from_this
。或者更好的是,通过为 std::set
实现允许与原始指针进行比较的比较函数,从容器中擦除而根本不构造 shared_ptr
。有关更多信息,请参阅:What are transparent comparators?
引用自cppreference
Constructing a new shared_ptr using the raw underlying pointer owned by another shared_ptr leads to undefined behavior.
当您这样做时:
sett.emplace( rp );
由于 implicit type conversion 创建了 shared_ptr
并赋予了 rp
指向的内存位置的所有权。让我们称之为 sp1(1) 其中 (1) 表示引用计数
当你这样调用时:
sett.erase( std::shared_ptr<int>( rp ) );
发生以下事件序列:
- 一个新的
shared_ptr
拥有rp
指向的内存。shared_ptr
认为内存的引用计数为1。sp2(1) erase
被调用。这将调用 default comparator。这可能会导致删除第一个 shared_ptr sp1。为 sp1 调用析构函数,引用计数将变为 0。由于引用计数为 0,因此内存被释放。
When erase returns sp2(1) 析构函数被调用(因为这是为函数调用临时创建的)。对于由 sp2
管理的内存,引用计数变为 0
析构函数不知道底层内存的命运已经被删除 sp1 再次调用内存上的 delete。 Double delete disaster 发生在此时。
这就是为什么,要么从创建内存时就shared_ptr
保留所有内容,要么为您的指针类型编写自定义比较器。