std::list<std::shared_ptr>::erase 得到一个 SIGSEGV

Posted

技术标签:

【中文标题】std::list<std::shared_ptr>::erase 得到一个 SIGSEGV【英文标题】:std::list<std::shared_ptr>::erase got an SIGSEGV 【发布时间】:2018-03-15 04:22:43 【问题描述】:

考虑以下代码:

#include <iostream>
#include <list>
#include <memory>

class Foo;

class Foo 
  public:
    Foo(int i): id(i) 
    typename std::list<std::shared_ptr<Foo>>::iterator i2;
    int id;
;

int main() 
  std::list<std::shared_ptr<Foo>> l;
  auto f1 = std::make_shared<Foo>(1);
  f1->i2 = l.end();
  l.insert(f1->i2, f1);
  std::cout << f1->id << std::endl;
  std::cout << l.size() << std::endl;
  for (auto i: l) 
    std::cout << i->id << std::endl;
  
  auto t = f1->i2;
  l.erase(t);
  std::cout << l.size() << std::endl;

执行这些代码会在l.erase(t)得到一个SIGSEGV,好像ListNode在shared_ptr减少它的ref_count之前就被销毁了。为什么?如何解决?

【问题讨论】:

【参考方案1】:

插入您的f1-&gt;i2 后向左l.end()。您尝试删除l.end(),这是不允许的。

修复很简单。更改insert 调用的行:

f1->i2 = l.insert(f1->i2, f1);

【讨论】:

插入list 不会使迭代器无效,否则你会发现:尝试erase end() 是无效的。 @Tas 你可以谷歌具体的实现,其中std::list::end() 在插入到末尾后失效。 我认为这是一个边缘情况。我缓存end() 是非常罕见的,而且我想不出有什么时候我缓存了end() 时有可能被删除。那将要求一个错误。【参考方案2】:

迭代器,在插入/删除操作之前初始化,操作后可能处于不确定状态,应再次更新。此外,您还试图通过本身指向 list.end() 的迭代器删除列表中的节点。要删除列表的最后一个元素,您可以使用std::list.pop_back();

auto t = f1->i2;
l.erase(--t); // Change this in your code - decrease the iterator

【讨论】:

以上是关于std::list<std::shared_ptr>::erase 得到一个 SIGSEGV的主要内容,如果未能解决你的问题,请参考以下文章

共享指针列表的共享指针

SAL 注释:std::shared_ptr 的 _Ret_maybenull_

在 lambda 中锁定 std::shared_ptr 的复制操作

这是 std::shared_ptr 的正确用法吗?

无法将参数 1 从 'std::shared_ptr<ChaseState>' 转换为 'std::shared_ptr<State<Cow>>

std::shared_mutex 是不是偏爱作者而不是读者?