大括号初始化器列表作为函数参数

时间:2018-09-12 15:41:53

标签: c++ c++11 arguments language-lawyer list-initialization

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

void acceptsFoo(foo a);

acceptsFoo({1, 2, 3});

那情况呢?

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

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

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

2 个答案:

答案 0 :(得分:0)

当使用braced-init-list初始化对象时,将其用于初始化对象。期间。

将braced-init-list应用于函数参数意味着按照列表初始化规则用值列表初始化该参数。返回braced-init-list时,它会根据列表初始化规则,使用值列表初始化返回值对象。

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

现在(C ++ 17之前的版本),如果您完成了acceptsFoo(foo{1, 2, 3});return foo{1, 2, 3},那将激起一个临时文件的创建,然后将其用于初始化参数/返回值。

答案 1 :(得分:0)

void acceptsFoo(foo a);

acceptsFoo({1, 2, 3});

否,在这种情况下不会出现临时情况。该参数直接从参数表达式中初始化。


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

就像参数一样,返回值直接从return语句中初始化。

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

那是从抽象机器的角度来看的;复制/移动实际上可以被忽略(这就是RVO的作用)。


但是,从C ++ 17开始,在语句foo f = returnsFoo();中将没有临时性,也没有复制/移动可忽略。另一方面,在语句returnsFoo();中,将创建一个临时文件(将其立即销毁)。