【问题标题】:std::list<std::shared_ptr>::erase got an SIGSEGVstd::list<std::shared_ptr>::erase 得到一个 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之前就被销毁了。为什么?如何解决?

【问题讨论】:

    标签: c++ list stl shared-ptr


    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-04
      • 2014-08-07
      • 2017-06-11
      • 1970-01-01
      • 2012-07-27
      • 2018-02-02
      相关资源
      最近更新 更多