理解对象直接初始化中转换序列与copy elision的作用
对象直接初始化中的Copy Elision规则解析
测试代码
#include <cstdio> class To { public: To() { std::puts("To default constructor"); } explicit To(int Input) : val(Input) { std::puts("To value constructor"); } To(To&& object) : val(object.val) { std::puts("To move constructor"); } ~To() { std::puts("To destructor"); } int val = -1; }; class From { public: explicit From(int Input) : val(Input) { std::puts("From value constructor"); } operator To() const { std::puts("From implicit conversion"); return To{val}; }; ~From() { std::puts("From destructor"); } int val = -1; }; int main() { To obj0(To{42}); // 场景1 std::puts("--------------"); To obj1(From{42}); // 场景2 std::puts("--------------"); }
场景1:To obj0(To{42});
输出
To value constructor
规则解析
你的判断完全正确,这是**C++17引入的保证式拷贝消除(Guaranteed Copy Elision)**在起作用,核心逻辑基于prvalue(纯右值)的语义变化:
To{42}是一个prvalue,它不代表一个已经存在的临时对象,而是描述了一个To对象的初始化方式。- 在直接初始化
obj0时,编译器会直接将这个prvalue的初始化逻辑应用到obj0的内存空间中,完全跳过临时对象的创建、移动/拷贝、销毁流程——也就是说,这个临时对象从一开始就不会被实体化,自然不需要右值实体化的步骤。这是C++标准强制要求的优化,无论编译器是否开启优化选项都必须执行。
场景2:To obj1(From{42});
输出
From value constructor
From implicit conversion
To value constructor
From destructor
规则解析
这里需要拆解两个层面的逻辑:
From对象无法被消除:From{42}是触发转换的源对象,转换运算符operator To()是From的成员函数,必须依赖一个已实体化的From对象才能调用。同时,From的构造/析构函数包含puts这类有可见副作用的操作,编译器无法违反as-if规则跳过这些步骤,因此From对象的构造和析构必须执行。转换内部的保证式拷贝消除:你预期的移动构造函数未被调用,是因为转换运算符中的
return To{val};触发了保证式拷贝消除:return To{val}返回的是一个prvalue,编译器会直接将这个To对象的构造逻辑应用到obj1的内存空间中,不需要先创建临时To对象再移动到obj1。因此最终调用的是To的值构造函数,而非移动构造。- 这里不存在"临时
To对象实体化后无法消除"的情况,因为prvalue的语义从根源上避免了临时对象的创建。
内容的提问来源于stack exchange,提问作者Oersted
相关产品推荐
相关产品推荐

