将初始值设定项列表作为函数参数

brace initializer list as function argument

本文关键字:列表 函数 参数      更新时间:2023-10-16

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

void acceptsFoo(foo a);
acceptsFoo({1, 2, 3});

那么这个案子呢?

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

我知道下面的代码,即使没有复制/移动 elision,也与调用构造函数相同,因此不会生成任何临时代码,但我找不到有关上述代码的信息。

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

当使用大括号初始化列表初始化对象时,它用于初始化对象。时期。

将大括号的 init-list 应用于函数参数意味着根据列表初始化的规则,使用值列表初始化该参数。当你返回一个大括号的初始化列表时,它用于根据列表初始化的规则,用值列表初始化返回值对象。

理论上没有临时对象被复制到参数/返回值中。

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

void acceptsFoo(foo a);
acceptsFoo({1, 2, 3});

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


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

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

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

这是从抽象机器的角度来看;复制/移动在实践中可以省略(这就是RVO所做的(。


但是从C++17开始,在声明foo f = returnsFoo();中,将没有临时的,也没有副本/移动到elide。另一方面,在语句中returnsFoo();,将有一个临时创建(立即销毁(。