在std::vector<std::list>中增删元素,是否会移动后续std::list?
关于
std::vector<std::list<T>>插入/删除元素时的对象移动问题 直接给结论:当你在std::vector<std::list<T>>的非末尾位置执行插入或删除操作时,vector中位于操作位置之后的std::list对象会被移动,但不会被拷贝——而且这个移动操作的成本低到几乎可以忽略不计。
详细解释
首先回忆std::vector的底层特性:它依赖连续数组存储元素,非末尾插入/删除时,必须将操作点之后的所有元素"挪到新位置"。但在C++11及以后的标准中,对于std::list这类支持移动语义的容器,这个"挪"的动作执行的是移动构造/移动赋值,而非拷贝操作。
为什么移动成本这么低?因为std::list本身只是个轻量级的"壳子"——它内部仅存储几个指针(比如指向链表头、尾节点的指针,以及分配器相关信息)。移动一个std::list时,只是把这些指针的值从旧对象转移到新对象,旧对象会被置为"空状态",但链表本身的节点数据完全不会被触碰、拷贝或移动。也就是说,链表的元素依然待在原来的内存位置,只是现在归vector里新位置的std::list对象管理了。
代码验证示例
#include <vector> #include <list> #include <iostream> int main() { std::vector<std::list<int>> vec; // 往vector中添加两个带元素的list vec.emplace_back(); vec.back().push_back(100); vec.emplace_back(); vec.back().push_back(200); // 在第一个位置插入一个空list vec.insert(vec.begin(), std::list<int>()); // 原第一个list现在在vec[1],元素依然存在 std::cout << "vec[1]的第一个元素:" << vec[1].front() << std::endl; // 输出100 // 原第二个list现在在vec[2],元素也不受影响 std::cout << "vec[2]的第一个元素:" << vec[2].front() << std::endl; // 输出200 return 0; }
从输出结果能看到,原来的链表元素完全不受vector操作的影响,只是vector中的std::list对象换了个存储位置而已。
补充说明
如果是在C11之前的环境(无移动语义支持),这个操作会触发std::list的拷贝构造,此时成本会很高——因为需要复制整个链表的所有节点。但目前主流编译器都已支持C11及以后标准,所以无需担心这种情况。
关键点总结
- 非末尾插入/删除会导致vector内后续的
std::list对象移动,而非拷贝 - 移动
std::list的成本极低,仅涉及几个指针的转移,不会触碰链表节点 - 链表内部的元素不会被移动或拷贝,它们的内存位置保持不变
内容的提问来源于stack exchange,提问作者tongbaiming
相关产品推荐
相关产品推荐

