【问题标题】:About C++ STL list class method erase()关于C++ STL列表类方法erase()
【发布时间】:2011-02-07 20:53:28
【问题描述】:

list::erase() 的文档说“调用析构函数之前”,这是什么意思?如果我想erase(it) 一个项目,然后再次push_back(*it) 该项目,因为它已经被破坏了,那会是非法的吗?

【问题讨论】:

  • 您确定std::list 是适合您用例的容器吗?链表提供理想性能特征的用例很少。
  • @James McNellis-基于上述用例,OP 似乎正试图在列表中移动元素。这将是一个非常好的用例,因为所有其他序列都需要 O(n) 来完成。
  • @templatetypedef:也许吧。我仍然会非常犹豫推荐std::list,而不知道它是如何被使用的。每个元素的大小、复制每个元素的成本、元素的数量以及拼接与迭代的相对频率都是重要的标准,我们不知道这些。

标签: c++ list stl


【解决方案1】:

是的,这将导致未定义的行为。一旦你erase 一个列表迭代器,你invalidate迭代器,这意味着它引用的对象不再保证是有效的。这意味着如果您随后尝试在任何上下文中使用迭代器,包括尝试取消引用该值以再次将其添加到列表中,它将导致未定义的行为,这可能会使程序崩溃、覆盖重要内存或什么都不做。

如果要将列表的元素移到后面,请考虑使用列表的splice 方法:

myList.splice(myList.end(), myList, it);

这会将元素移动到末尾而不进行复制。

【讨论】:

  • 这不会比单个元素拼接更多吗?检查了文档。你是对的,这将做完全正确的事情。
  • +1;也是我错过的一种方法。另请参阅对一系列迭代器执行相同操作的版本。
【解决方案2】:

容器中的元素在从容器中移除时被销毁。如果您想在将对象从容器中移除后保留该对象,则需要对其进行复制并改用该副本。

您建议的代码:

v.erase(it);
v.push_back(*it);

无效,因为it 在擦除后无效。迭代器失效后就不能再使用了。

【讨论】:

    【解决方案3】:

    混合使用擦除和迭代器可能是一件非常棘手的事情。完成擦除后各种迭代器的有效性可能因容器而异。如果你想做erasepush_back,你应该做的事情是先保存*it 中的内容的副本,然后在执行push_back 时使用该副本。

    【讨论】:

      【解决方案4】:

      通过销毁它然后从列表中删除对它的引用来擦除该项目。如果要保留该项目,则需要在调用擦除之前对其进行复制。所有这些都表明 std::list 可能不是满足您需求的正确容器。

      【讨论】:

        猜你喜欢
        • 2010-10-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多