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

C++ vector调用push_back插入3元素触发6次拷贝构造的原因

现象原理

你观察到的6次拷贝构造,是std::vector动态扩容时拷贝旧元素、插入临时对象时拷贝入容器两个行为叠加的结果,和vector的内存管理逻辑直接相关。
std::vector是基于连续内存存储的序列容器,初始状态下预留容量为0,当插入新元素时发现剩余容量不足,就会申请一块更大的连续新内存,把旧内存上存储的所有元素拷贝/移动到新内存,释放旧内存后再完成新元素的插入。另外你定义的vertex结构体没有自定义移动构造函数,push_back接收右值临时对象时不会触发移动语义,仍然会调用拷贝构造函数完成对象复制。
你当前使用的编译环境下vector扩容倍数为2(GCC、Clang均采用该策略,MSVC采用1.5倍扩容,最终拷贝计数会有差异),逐次插入的拷贝触发逻辑如下:

逐次插入的拷贝计数拆解
  • 第一次执行vertices.push_back(vertex(1, 2, 3))
    • 栈上生成第一个vertex临时对象
    • vector初始容量为0,首次插入申请能容纳1个元素的内存
    • 将临时对象拷贝构造到vector的新内存位置,触发第1次拷贝
    • 执行完成后vector容量为1,存储元素1个
  • 第二次执行vertices.push_back(vertex(4, 5, 6))
    • 栈上生成第二个vertex临时对象
    • 当前容量1不足以容纳2个元素,触发扩容:申请能容纳2个元素的新内存块
    • 将旧内存中存储的1个vertex元素拷贝到新内存,触发第2次拷贝
    • 释放旧内存块
    • 将本次的临时对象拷贝构造到新内存的第二个位置,触发第3次拷贝
    • 执行完成后vector容量为2,存储元素2个
  • 第三次执行vertices.push_back(vertex(7, 8, 9))
    • 栈上生成第三个vertex临时对象
    • 当前容量2不足以容纳3个元素,再次触发扩容:申请能容纳4个元素的新内存块
    • 将旧内存中存储的2个vertex元素依次拷贝到新内存,分别触发第4、第5次拷贝
    • 释放旧内存块
    • 将本次的临时对象拷贝构造到新内存的第三个位置,触发第6次拷贝
    • 执行完成后vector容量为4,存储元素3个

三次插入累计触发6次拷贝,和你观察到的输出完全一致。

拷贝优化方案

你可以通过两种方式消除不必要的拷贝:

  • 提前预分配容量:在插入元素前调用vertices.reserve(3),直接申请足够存3个元素的内存,插入过程中不会触发扩容,可消除3次扩容带来的旧元素拷贝,总拷贝次数降到3次
  • 改用原位构造方法:将push_back()替换为emplace_back(),直接传入构造函数需要的参数(即写为vertices.emplace_back(1,2,3)),vector会直接在自身的内存位置调用vertex的构造函数,不需要先生成临时对象再拷贝,配合reserve(3)使用可以把拷贝构造的触发次数降到0。

附可直接运行的复现代码:

#include <iostream>
#include <vector>

struct vertex{
    float x, y, z;

    vertex(float x, float y, float z) : x(x), y(y), z(z){

    }

    vertex(const vertex& other) : x(other.x), y(other.y), z(other.z){
        std::cout << "copied" << std::endl;
    }
};


int main(){
    std::vector<vertex> vertices;

    vertices.push_back(vertex(1, 2, 3));
    vertices.push_back(vertex(4, 5, 6));
    vertices.push_back(vertex(7, 8, 9));
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 15:57:11