You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,但实际上:

  1. 执行splice(B.end(), A, p, q)后,A中[p, q)范围内的所有元素(也就是A的全部元素1、2、3)都被转移到B的末尾。
  2. A变成空链表,此时A.begin()等于A.end()。
  3. 而p这个迭代器指向的是原来的节点(现在属于B),所以它和A.begin()(空链表的尾后迭代器)不再相等,但p本身完全有效,可以正常访问B中的元素。

总结迭代器有效性规则

针对std::list::splice的所有重载版本,迭代器有效性统一遵循:

  • 指向被转移元素的迭代器、引用:有效,归属目标容器。
  • 源容器中未被转移元素的迭代器、引用:有效。
  • 目标容器的所有迭代器、引用:有效(因为只是插入节点,不会打乱原有链表结构)。
  • 源容器的end()迭代器:始终有效。

内容的提问来源于stack exchange,提问作者tdenniston

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:04:33