大括号初始值设定项列表作为函数参数

brace initializer list as function argument

忽略编译器中的 copy/move 省略,我想知道以下代码(假设 foo 有一个接受三个整数的构造函数)是否 "syntactically" 创建一个临时对象然后 copy/move初始化函数参数,或者直接调用构造函数:

void acceptsFoo(foo a);

acceptsFoo({1, 2, 3});

那么这个案例呢?

//ignoring RVO optimization
foo returnsFoo()
{
   return {1, 2, 3};
}

我知道下面的代码,即使没有 copy/move 省略,也与调用构造函数相同,因此不会生成任何临时文件,但我找不到有关上面代码的信息。

foo = { 1, 2, 3 } //assuming the constructor is non-explicit
foo { 1, 2, 3 }

当braced-init-list用于初始化对象时,它用于初始化对象。期间.

将花括号初始化列表应用于函数参数意味着根据列表初始化规则使用值列表初始化该参数。当你 return 花括号初始化列表时,它用于根据列表初始化规则用值列表初始化 return 值对象。

理论上没有临时对象被复制到 parameter/return 值中。

现在(C++17 之前的版本),如果你已经完成了 acceptsFoo(foo{1, 2, 3});return foo{1, 2, 3},那么这将引发一个临时的创建,然后将用于初始化 parameter/return值。

void acceptsFoo(foo a);

acceptsFoo({1, 2, 3});

不,在这种情况下不会有临时的。参数直接从参数表达式初始化。


//ignoring RVO optimization
foo returnsFoo()
{
   return {1, 2, 3};
}

就像参数的情况一样,return 值直接从 return 语句初始化。

但是,函数调用表达式的结果将是一个临时对象,是的。因此,如果您这样调用该函数: foo f = returnsFoo(); 将创建两个实例。首先 return 值从大括号初始化器初始化,然后变量绑定对象从临时对象复制初始化(通过移动,如果 foo 是可移动的)。

那是从抽象机的角度; copy/move 在实践中可以省略(这就是 RVO 所做的)。


但是从 C++17 开始,在语句 foo f = returnsFoo(); 中,将没有临时的,也没有 copy/move 可以省略。另一方面,在语句 returnsFoo(); 中,会创建一个临时对象(立即销毁)。