emplace_back中使用聚合初始化的底层原理及拷贝构造调用疑问
emplace_back结合聚合初始化的拷贝构造疑问及底层逻辑
核心结论
你当前代码里的A{1,2,3}不会触发拷贝构造函数,但会触发编译器自动生成的默认移动构造函数。如果想完全避免移动/拷贝操作,应该直接传递聚合初始化的参数给emplace_back。
底层执行逻辑拆解
1. 聚合初始化A{1,2,3}的过程
你的结构体A属于聚合类型(满足:无用户定义构造函数、无私有/保护非静态成员、无基类、无虚函数等条件),因此A{1,2,3}执行的是聚合初始化:
- 直接将
1、2、3依次赋值给A的成员x、y、z; - 这个过程不会调用任何构造函数(不管是用户定义还是编译器生成的),属于直接内存赋值初始化。
2. emplace_back(A{1,2,3})的执行过程
emplace_back的设计初衷是接收构造目标对象的参数,然后在vector的内存空间中直接构造对象。但你这里传的是一个已构造好的临时A对象:
- 编译器会将这个临时对象作为右值传递给
emplace_back的万能引用参数; emplace_back会在vector的内存(若需要扩容则先分配新内存)中,调用A的移动构造函数,将临时对象的成员值转移到新对象中;- 由于你未定义移动构造函数,编译器会自动生成默认移动构造(当无用户定义的拷贝构造、移动构造、赋值运算符时,编译器会生成默认版本)。对于
int这类基本类型,移动操作等同于值拷贝,但不会触发你注释掉的拷贝构造函数。
3. 最优写法:完全避免移动/拷贝
若要充分利用emplace_back直接构造的特性,应直接传递聚合初始化的参数,而非先构造临时对象:
vec.emplace_back(1, 2, 3);
这种写法下,emplace_back会直接在vector的内存空间中对A执行聚合初始化,完全跳过临时对象的创建和移动/拷贝步骤,效率更高。
聚合初始化的关键规则
聚合类型必须满足以下条件(缺一不可):
- 无用户定义的构造函数;
- 无私有或保护的非静态数据成员;
- 无基类;
- 无虚函数;
- 无
=delete/=default之外的构造函数(C++11及以后标准)。
只有符合这些条件,才能使用聚合初始化语法直接初始化成员。
内容的提问来源于stack exchange,提问作者Yousef Irshaid
相关产品推荐
相关产品推荐

