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

为何在C++17中无法使用emplace_back(...)替代push_back({...})?

为何在C++17中无法使用emplace_back(...)替代push_back({...})?

这个问题其实戳中了C++17里聚合类型和emplace_back机制的一个小坑,我来给你掰扯清楚:

首先,你定义的struct A是一个聚合类型——它没有显式声明的构造函数、没有基类、没有虚函数,完全符合C++里聚合类型的定义。

先看为什么push_back({1,2})能正常工作:
当你写v.push_back({1,2})时,编译器会把{1,2}识别为聚合初始化的参数列表,直接创建一个临时的A对象,然后push_back接收这个临时对象(在C++11及以后还会自动移动,避免拷贝开销)。这完全契合聚合类型的初始化规则,所以编译器不会有任何意见。

那为什么emplace_back(1,2)会报错呢?
emplace_back的核心设计是把参数完美转发给元素的构造函数,直接在容器预留的内存里构造对象,避免创建临时对象。但问题在于,聚合类型的初始化是通过聚合初始化完成的,而不是调用构造函数——你的A根本没有一个能接受两个int参数的构造函数啊!在C++17中,emplace_back还不支持用多个独立参数来触发聚合初始化,它只会死磕“有没有对应的构造函数”,找不到自然就会抛出一大串你看不懂的编译错误。

那要怎么让emplace_back(1,2)正常工作呢?有两个简单的解决方案:

  • 给A添加一个显式的构造函数,比如这样:
#include <vector>
int main() {
    struct A{
        int x;
        int y;
        A(int x_, int y_) : x(x_), y(y_) {} // 新增构造函数
    };
    std::vector<A> v;
    v.emplace_back(1, 2); // 现在可以正常工作了
    v.push_back({1, 2});
    return 0;
}

这样emplace_back(1,2)就能找到这个构造函数,把参数转发过去直接构造对象,完全符合它的设计初衷。

  • 升级到C20标准:C20扩展了emplace_back的能力,支持对聚合类型使用多个参数进行聚合初始化,你的原始代码不用做任何修改就能正常编译运行。

另外还有个小技巧:如果你不想加构造函数又想在C++17里用emplace_back,可以直接传一个聚合初始化的A对象,比如v.emplace_back(A{1,2}),不过这样其实和push_back一样会创建临时对象,失去了emplace_back原本的性能优势,所以不太推荐。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 08:54:37