在列表内或跨多个列表添加、删除和移动元素不会使迭代器或引用无效。只有当相应的元素被删除时,迭代器才会失效。
事实上,排序元素时就是这种情况。来自cppreference 文章std::list::sort:
该函数的不同之处还在于
std::sort它不需要列表的元素类型是可交换的,保留所有迭代器的值,并执行稳定的排序。
但是如何在保留所有迭代器的值的同时任意交换两个元素的位置?
例如,假设我有一个列表:
std::list<int> l({1, 2, 3, 4});
auto it = l.begin(), jt = ++l.begin();
Run Code Online (Sandbox Code Playgroud)
现在it指向1和jt指向2。我可以重新排列这个列表,使之2出现在之前1,但it仍指向1吗?
我可以:
std::swap(*it, *jt);
Run Code Online (Sandbox Code Playgroud)
但是,虽然2会在 之前1,我不会保留迭代器的值,因为显然it会指向2.
鉴于 cppreference 的前面引用,我想应该有可能实现我想要实现的目标;但是怎么样?
编辑:为了清楚起见:再举一个例子:
std::list<int> l({2, 1, 3, 4, 5});
auto it = l.begin(), jt = ++l.begin();
Run Code Online (Sandbox Code Playgroud)
现在it指向2和jt指向1。
std::list::sort 具有我正在寻找的语义:
l.sort();
Run Code Online (Sandbox Code Playgroud)
现在列表的顺序是:1, 2, 3, 4, 5,但是it仍然指向2并且jt仍然指向1。
另一方面,std::swap(it, jt)也std::swap(*it, *jt)没有我想要的语义。调用它们中的任何一个都会it指向1和jt指向2。(ideone证明)
但是如何在保留所有迭代器的值的同时任意交换两个元素的位置?
按照@cpplearner 的建议,使用.splice().
它可以对单个元素或范围进行操作。它还可以跨列表传输元素。
这是一个演示如何移动单个元素的简单示例。
std::list<int> list{1,2,3,4,5};
// This element will be moved
auto source = std::find(list.begin(), list.end(), 4);
// It will be inserted before this element
auto destination = std::find(list.begin(), list.end(), 2);
list.splice(destination, list, source);
// ^ ^
// | `- A list to move from
// `- A list to move to
// Prints `1 4 2 3 5`.
for (int it : list) std::cout << it << ' ';
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2598 次 |
| 最近记录: |