C++11中std::list执行splice操作后迭代器失效问题咨询
关于C++11 std::list::splice对迭代器的影响解析
我来帮你拆解这个问题——std::list的splice操作本质是链表节点的直接转移,不会销毁或重新分配节点,这是理解它对迭代器影响的核心。先看你的示例代码(我补充了后续测试代码帮你更直观验证):
#include <iostream> #include <list> int main() { std::list<int> A({1, 2, 3}); std::list<int> B; auto p = A.begin(), q = A.end(); auto p_copy = p, q_copy = q; // 输出为True std::cout << "p == A.begin()? " << (p == A.begin()) << std::endl; // 输出为True std::cout << "p_copy == A.begin()? " << (p_copy == A.begin()) << std::endl; B.splice(B.end(), A, p, q); // 新增测试验证迭代器状态 std::cout << "A is empty? " << A.empty() << std::endl; // 输出True std::cout << "*p = " << *p << std::endl; // 输出1,p依然有效,指向B的第一个元素 std::cout << "p == A.begin()? " << (p == A.begin()) << std::endl; // 输出False std::cout << "p == B.begin()? " << (p == B.begin()) << std::endl; // 输出True std::cout << "q == A.end()? " << (q == A.end()) << std::endl; // 输出True return 0; }
splice操作的核心特性
splice只是把源容器中指定范围的节点直接移动到目标容器的指定位置,整个过程不会发生元素的构造、销毁,也不会重新分配内存。因此:
- 指向被转移元素的迭代器(比如你的
p、p_copy)依然有效,但它们现在指向的是目标容器B中的对应元素,不再属于源容器A。 - 源容器中未被转移元素的迭代器、引用依然有效(但这个例子里A的元素全被转移了,所以A变成空链表)。
- 源容器的**尾后迭代器(end())**始终有效,不管元素是否被转移(比如你的
q、q_copy,原本就是A的end,在A空了之后,A.begin() == A.end(),所以q依然等于A.end())。
为什么你的预期会有偏差?
你可能以为splice后p仍然关联着A的begin,但实际上:
- 执行
splice(B.end(), A, p, q)后,A中[p, q)范围内的所有元素(也就是A的全部元素1、2、3)都被转移到B的末尾。 - A变成空链表,此时
A.begin()等于A.end()。 - 而
p这个迭代器指向的是原来的节点(现在属于B),所以它和A.begin()(空链表的尾后迭代器)不再相等,但p本身完全有效,可以正常访问B中的元素。
总结迭代器有效性规则
针对std::list::splice的所有重载版本,迭代器有效性统一遵循:
- 指向被转移元素的迭代器、引用:有效,归属目标容器。
- 源容器中未被转移元素的迭代器、引用:有效。
- 目标容器的所有迭代器、引用:有效(因为只是插入节点,不会打乱原有链表结构)。
- 源容器的end()迭代器:始终有效。
内容的提问来源于stack exchange,提问作者tdenniston
相关产品推荐
相关产品推荐

