在C ++ 11中,“ return {}”语句是什么意思?


115

声明是什么

return {};

在C ++ 11中指示,以及何时使用它代替(例如)

return NULL;

要么

return nullptr;

59
它返回函数返回类型的默认构造的实例。
理查德·霍奇斯

还是简单return;而没有价值?
i486

不,正如讨论所揭示的那样,如果您的函数应返回某些内容(即非空返回类型),而您只写,则是编译时错误。return; 另一方面return{};,如果您具有返回类型,则是有效的。
Pedia'9

@Pedia并非总是如此,某些对象将需要构造参数
MM

Answers:


108

return {};表示“返回具有空列表初始化器初始化的函数返回类型的对象”。确切的行为取决于返回的对象的类型。

cppreference.com(因为OP被标记为C ++ 11,所以我排除了C ++ 14和C ++ 17中的规则;有关更多详细信息,请参阅链接):

  • 如果braced-init-list为空且T是具有默认构造函数的类类型,则将执行值初始化。
  • 否则,如果T是聚合类型,则执行聚合初始化。
  • 否则,如果T是std :: initializer_list的特殊化,则根据上下文从braced-init-list直接初始化或复制初始化T对象。
  • 否则,将分两个阶段考虑T的构造函数:

    • 检查所有将std :: initializer_list作为唯一参数,或将第一个参数(如果其余参数具有默认值)作为第一个参数的构造函数,并通过重载解析将其与类型为std :: initializer_list的单个参数匹配
    • 如果前一阶段不产生匹配,则T的所有构造函数都将针对由braced-init-list元素组成的参数集参与重载解析,并且限制为仅允许非缩小转换。如果此阶段生成一个显式构造函数作为复制列表初始化的最佳匹配,则编译会失败(请注意,在简单的复制初始化中,根本不考虑显式构造函数)。
  • 否则(如果T不是类类型),如果braced-init-list仅具有一个元素,并且T不是引用类型或与该元素类型兼容的引用类型,则T为直接-已初始化(在直接列表初始化中)或副本初始化(在复制列表初始化中),但不允许缩小转换。

  • 否则,如果T是与元素类型不兼容的引用类型。(如果引用是非常量左值引用,则失败)
  • 否则,如果braced-init-list没有元素,则T被值初始化。

在C ++ 11之前,对于返回a的函数std::string,您应该编写:

std::string get_string() {
    return std::string();
}

在C ++ 11中使用大括号语法,您无需重复该类型:

std::string get_string() {
    return {}; // an empty string is returned
}

return NULL并且return nullptr应在函数返回指针类型时使用:

any_type* get_pointer() {
    return nullptr;
}

但是,NULL自C ++ 11起不推荐使用,因为它只是整数值(0)的别名,而nullptr实际上是指针类型:

int get_int() {
    return NULL; // will compile, NULL is an integer
}

int get_int() {
    return nullptr; // error: nullptr is not an integer
}

91

这可能令人困惑:

int foo()
{
  return {};   // honestly, just return 0 - it's clearer
}

这可能不是:

SomeObjectWithADefaultConstructor foo()
{
  return {};
  // equivalent to return SomeObjectWithADefaultConstructor {};
}

9
因此,如果返回类型没有默认构造函数,则是编译时错误,对吗?
Pedia'9

10
如果返回类型是不具有非显式默认构造函数且不是聚合的类,则这是编译错误。
Oktalist

3
如果该类型具有initializer_list构造函数,那么在没有默认构造函数可用的情况下,将不会使用该构造函数吗?
celtschk

4
“可能令人困惑”?这就是为什么某些未命名的灵魂提到“那是C ++的That肿ob亵”吗?这样做所节省的击键次数是否可以证明其缺乏清晰度的可能性?这是一个真诚的问题。请用实际例子说服我。
MickeyfAgain_BeforeExitOfSO 2016年

4
return {}不等于return SomeObjectWithADefaultConstructor{};
MM

26

return {};表示这{}返回值的初始化程序。返回值使用空列表进行列表初始化。


这是基于C ++标准中的[stmt.return] 返回值的一些背景:

对于按值返回的函数(即返回类型不是引用而不是引用void),有一个临时对象称为return value。该对象由该return语句创建,其初始化程序取决于return语句中的内容。

返回值将一直保留到调用该函数的代码中的完整表达式结束为止。如果它具有类类型,则其析构函数将运行,除非调用者直接将引用绑定到其上以延长其生存期。

可以通过两种不同的方式初始化返回值:


假设T是函数的返回类型,则请注意return T{};return {}:不同:在前者中,T{}创建了一个临时项,然后从该临时项中复制初始化了返回值

如果T没有可访问的copy / move-constructor,将无法编译,但是return {};即使不存在这些构造函数,也将成功。因此,return T{};尽管这是一个复制省略上下文,但可能不会显示出复制构造函数等的副作用。


这是C ++ 14(N4140 [dcl.init.list] / 3)中列表初始化的简要概述,其中初始化程序是一个空列表:

  • 如果T是聚合,则每个成员如果有一个,则从其大括号或相等初始化器进行初始化,否则就好像通过{} (因此,递归地应用这些步骤)。
  • 如果T是具有用户提供的默认构造函数的类类型,则将调用该构造函数。
  • 如果T是具有隐式定义或= defaulted默认构造函数的类类型,则将对象初始化为零,然后调用默认构造函数。
  • 如果Tstd::initializer_list,则返回值为空白列表。
  • 否则(即为T非类类型-返回类型不能为数组),返回值将初始化为零。

首先是Aggregate init,它使用递归地初始化每个成员{},该成员可能不是值初始化。
TC

@TC对,我通过cppreference去了,但是忽略了“直到C ++ 14”
MM

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.