问题 std :: list - 移动时失效的迭代器是什么?


std::list 迭代器有一些非常好的属性 - 当删除任何其他元素时,添加新元素时甚至交换2个列表时它们仍然有效(迭代器失效规则)!

考虑以下代码行为并且迭代器是通过指向实际节点的指针形式实现的,当移动列表时它不会改变,我的猜测是迭代器在新容器中仍然有效 std::list 移动了,但我也可以通过访问实际具有“预期”值的无效内存进入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 被感动?其他容器怎么样?


10442
2017-10-15 09:21


起源

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


答案:


仅适用于容器 swap 保证迭代器保持有效(并指向交换的容器)。

对于 std::list,特殊会员功能 splice() 保证迭代器保持其预期的含义。

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

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


9
2017-10-15 09:28



在调试模式下引用容器的好处。大多数实现都是为了帮助调试超出范围/无效的迭代器。 - Felics
这个调试实现不可能满足 swap 复杂性要求(常数)。 - zch
@zch:那是真的。我认为MS迭代器使用双重间接来实现有效的交换;它们有可能在行动中保持有效。 - Kerrek SB