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

C++使用emplace_back和reserve向vector存对象仍出现非预期拷贝问题

问题原因

你对emplace_back的功能存在误解,加上类定义的规则限制,共同导致了多余拷贝的出现:

  1. emplace_back使用方式错误
    emplace_back的核心作用是接收构造函数的参数,直接在vector分配的内存空间中原地构造对象,不需要提前创建对象实例。你传入已经构造完成的Vertex(1,2,3)临时对象时,已经额外完成了一次栈上对象创建,后续必须通过拷贝/移动操作把这个临时对象的数据写入vector的内存,完全没有用到emplace_back的原地构造能力,此时它的行为和push_back完全一致。
  2. 自定义拷贝构造抑制了默认移动构造生成
    C++标准规定,只要用户显式定义了拷贝构造函数,编译器就不会自动生成默认的移动构造函数。因此即便你用std::move把对象转为右值传入,也没有匹配的移动构造可以调用,最终还是会落到拷贝构造上,所以始终会打印COPIED!。

解决方案

完全消除拷贝的最优写法

直接把构造函数的参数传给emplace_back即可,不需要提前创建对象:

int main()
{
    std::vector<Vertex> vert;
    vert.reserve(3);
    // 直接传构造参数,原地构造,无任何拷贝/移动
    vert.emplace_back(1, 2, 3);
    vert.emplace_back(4, 5, 6);
    vert.emplace_back(7, 8, 9);
    return 0;
}

这种写法会直接在vector预留的内存中调用Vertex的三参数构造函数,不会触发任何拷贝操作,运行后不会有COPIED!输出。

针对已有对象的场景

如果确实需要把已经创建好的对象存入vector,可以给Vertex类显式定义移动构造函数:

struct Vertex
{
    size_t x, y, z;

    Vertex(size_t x, size_t y, size_t z)
    {
        this->x = x;
        this->y = y;
        this->z = z;
    }

    Vertex(const Vertex& v)
        : x(v.x), y(v.y), z(v.z)
    {
        std::cout << "COPIED!\n";
    }

    // 新增移动构造函数
    Vertex(Vertex&& v) noexcept
        : x(std::move(v.x)), y(std::move(v.y)), z(std::move(v.z))
    {
        std::cout << "MOVED!\n";
    }
};

添加移动构造后,你再用vert.emplace_back(std::move(Vertex(1,2,3)))这类写法时,就只会调用开销极低的移动构造,不会触发拷贝。

另外补充:你多次对同一个左值对象调用std::move属于错误用法,对象第一次被移动后就处于合法但值不确定的状态,后续操作不符合C++规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 17:15:03