list::splice不能直接拼接两个独立list,因为它是移动语义操作,仅重连节点指针而不复制,要求源list非常量、未析构且与目标同类型;若需保留源内容,应改用insert。

list::splice 为什么不能直接拼接两个独立 list?
因为 splice 是移动语义操作,它不复制节点,而是把源链表的节点“摘下来”挂到目标链表里——所以源 list 必须和目标是同一个容器类型、且**不能是 const 或临时对象**。最常见错误是写成:list1.splice(list1.end(), list2) 后发现 list2 变空了,但你本意可能是“保留 list2”,或者更糟:对已析构的 list2 调用 splice 导致未定义行为。
正确调用 splice 的三种典型场景
所有合法调用都要求:目标 list 和源 list 是同一类型(比如都是 std::list<int></int>),且源不能是 const,也不能在调用后立即被销毁。
- 把整个
list2拼到list1尾部:list1.splice(list1.end(), list2)→list2变为空 - 把
list2的某一段(迭代器区间)拼到list1中间:list1.splice(it, list2, begin_it, end_it)→ 这段节点从list2移出,插入到list1的it前 - 把
list2的单个节点(通过迭代器)拼过去:list1.splice(it, list2, iter)→iter必须指向list2中的有效节点
想合并但又不想清空原 list?得手动 copy
splice 天然不支持“复制式合并”。如果需要保留 list2 内容,就不能用 splice,而得用 insert 或循环 push_back:
list1.insert(list1.end(), list2.begin(), list2.end());
注意:这会触发节点复制(调用元素类型的拷贝构造函数),性能比 splice 差,且要求元素可拷贝;而 splice 是 O(1) 时间,insert 是 O(N)。另外,list2 保持不变,适合只读合并场景。
立即学习“C++免费学习笔记(深入)”;
容易忽略的兼容性细节
不同标准版本下行为一致,但有两点必须检查:
- 源
list和目标list的分配器(allocator)必须相等,否则编译失败(C++11 起强制要求) - 若元素类型有自定义移动构造函数,
splice不会调用它——因为不涉及构造/析构,只是指针重连;但insert会调用拷贝或移动构造 - 迭代器有效性:被
splice的节点的迭代器在操作后仍有效(指向新位置),但源list的end()迭代器失效(因 size 改变)
真正麻烦的往往不是语法,而是误以为 splice 是“安全粘贴”,结果在多线程里共享了 list 对象,或在 lambda 捕获后对已 move 的 list 调用 splice —— 那时连编译器都救不了你。


















