【问题标题】:std::list - are the iterators invalidated on move?std::list - 迭代器是否在移动时失效?
【发布时间】:2014-10-15 09:21:07
【问题描述】:

std::list 迭代器有一些非常好的属性——它们在任何其他元素被删除、添加新元素甚至交换 2 个列表时仍然有效 (Iterator invalidation rules)!

考虑到以下代码行为,并且迭代器是通过指向实际节点的指针形式实现的,该指针在移动列表时不会改变,我的猜测是当@987654323 时迭代器在新容器中仍然有效@ 被移动了,但我也可以通过访问实际上具有“预期”值的无效内存进入 UB 区域。

std::list<int> l1{3, 2, 1};
std::list<int> l2;

auto it = std::prev(l1.end());
std::cout<<l1.size()<<" "<<l2.size()<<" "<<*it<<std::endl;

l2 = std::move(l1);
std::cout<<l2.size()<<" "<<*it<<std::endl;

3 0 1
3 1

如果移动std::list 时迭代器仍然有效,标准是否保证?其他容器呢?

【问题讨论】:

  • 我以前见过类似的问题。 C++11 明确保证swap 不会失效,但不保证移动。不过,它们通常具有相同的效果。
  • 我会说它们可能会因不同的分配器而失效。

标签: c++ c++11 c++14


【解决方案1】:

对于一般的容器,只有swap 保证迭代器保持有效(并指向被交换的容器)。

对于std::list,特殊成员函数splice() 保证迭代器保持其预期含义。

一般来说,从右值构造容器并不能保证迭代器;唯一的一般要求是新容器与最初构造它的容器具有“相同的值”。

(您可以想象存储对容器的引用的调试迭代器实现,并且该引用在移动后会变得悬空。)

【讨论】:

  • 在调试模式下对容器的引用很好。大多数实现这样做是为了帮助调试超出范围/无效的迭代器。
  • 此调试实现不可能满足swap 复杂性要求(常数)。
  • @zch:确实如此。我认为 MS 迭代器使用双重间接来实现高效交换;它们有可能在移动时也保持有效。
猜你喜欢
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
  • 2011-04-14
  • 1970-01-01
  • 2013-06-24
  • 1970-01-01
  • 1970-01-01
  • 2011-05-06
相关资源
最近更新 更多