非聚合类型成员初始化能否实现拷贝消除与原地构造?
非聚合类型成员的原地构造实现方案
当然可以实现非聚合类型成员的无拷贝/移动原地构造,并非只有聚合类型能做到。核心思路是避免先构造独立的成员对象再传递,而是直接将构造成员所需的参数传递到成员的内存位置,让编译器在原地调用成员的构造函数。结合你给出的S类型,具体方案如下:
问题复现:原有非聚合类的拷贝/移动开销
先看典型的错误写法,这类写法会产生不必要的拷贝或移动:
// 存在拷贝/移动开销的非聚合类 struct NotAgg { S s; // 先构造S对象作为参数,再拷贝/移动给成员s NotAgg(S s_) : s(s_) {} }; // 调用时的输出: // 1-arg ctor(构造临时S对象) // move ctor(临时对象移动给成员s) // dtor(临时对象销毁) // dtor(成员s销毁) NotAgg na(S("test"));
方案1:直接传递成员构造参数到初始化列表
在类的构造函数中,直接接收成员S所需的构造参数,然后在初始化列表里用这些参数原地构造成员:
struct NotAggFixed { S s; // 接收S的构造参数,直接原地构造成员s explicit NotAggFixed(std::string x) : s(std::move(x)) {} }; // 调用时的输出: // 1-arg ctor(直接在成员s的位置构造) // dtor(成员s销毁) NotAggFixed naf("hello");
这里没有中间S对象,编译器会直接在NotAggFixed的S成员内存位置调用S的单参数构造函数,完全避免拷贝/移动。
方案2:完美转发模板构造函数(通用场景)
如果想要支持任意参数组合来构造成员S,可以使用模板构造函数配合完美转发,实现对成员构造参数的无损耗传递:
struct NotAggForward { S s; // 完美转发任意参数,原地构造成员s template<typename... Args> explicit NotAggForward(Args&&... args) : s(std::forward<Args>(args)...) {} }; // 两种调用方式均无拷贝/移动: NotAggForward naf1("hello"); // 直接用字符串字面量构造S NotAggForward naf2(std::string("world")); // 用右值字符串构造S
模板参数会匹配传入的参数类型,std::forward保持参数的左值/右值属性,最终直接在成员s的内存位置调用对应版本的S构造函数,无中间对象产生。
核心原理
聚合类型的聚合初始化本质是直接在成员内存位置构造对象;而非聚合类型通过构造函数的初始化列表,将构造成员的参数直接传递到成员的构造逻辑中,同样能让编译器在原地完成成员初始化,跳过拷贝/移动步骤。
内容的提问来源于stack exchange,提问作者mCoding
相关产品推荐
相关产品推荐

