【问题标题】:brace initializer list as function argument大括号初始值设定项列表作为函数参数
【发布时间】:2019-02-17 07:40:57
【问题描述】:

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

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 }

【问题讨论】:

  • 您想要理论答案还是实际答案?
  • 理论上的,如果可能的话。我知道实际上它总是会被任何适当的编译器忽略。
  • 在这种情况下,您应该提供一个完整的示例(没有“假设 X 存在”)并用语言律师标记您的问题。
  • @A.S.语言要求某些省略。忽略 all 省略不会给你一个有意义的答案。虽然你可以假设 optional 省略不会发生。
  • 最后,将您的问题绑定到 c++98、c++11、c++14、c++17 或 c++2a。

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


【解决方案1】:

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

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

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

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

【讨论】:

【解决方案2】:
void acceptsFoo(foo a);

acceptsFoo({1, 2, 3});

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


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

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

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

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


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

【讨论】:

    猜你喜欢
    • 2011-05-31
    • 1970-01-01
    • 2020-12-04
    • 2018-09-06
    • 1970-01-01
    • 2021-11-21
    • 2014-05-13
    • 1970-01-01
    • 2015-01-24
    相关资源
    最近更新 更多