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

声明是什么?

return {}; 

在C ++ 11中指出,何时使用它而不是(说)

 return NULL; 

要么

 return nullptr; 

return {}; 指示“返回函数返回types的对象,初始化为一个空的列表初始值设定项 ”。 确切的行为取决于返回的对象的types。

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

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

    • 所有将std :: initializer_list作为唯一参数的构造函数,或者如果其余参数具有默认值,则作为第一个参数进行检查,并通过重载parsing匹配types为std :: initializer_list的单个参数
    • 如果前一阶段没有产生匹配,T的所有构造函数都参与由braced-init-list元素组成的参数集的重载parsing,限制条件是只允许非缩小转换。 如果这个阶段产生一个明确的构造函数作为复制列表初始化的最佳匹配,编译失败(注意,在简单的复制初始化中,根本不考虑显式构造函数)。
  • 否则(如果T不是类types),如果braced-init-list只有一个元素,并且T不是一个引用types,或者是一个与元素types兼容的引用types,初始化(在直接列表初始化中)或复制初始化(在复制列表初始化中),除了不允许缩小转换之外。

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

在C ++ 11之前,对于一个返回一个std::string的函数,你会写:

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

使用C ++ 11中的大括号语法,您不需要重复types:

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

当函数返回一个指针types时, return NULLreturn nullptr

 any_type* get_pointer() { return nullptr; } 

但是,自从C ++ 11以来, NULL被弃用了,因为它只是一个整数值(0)的别名,而nullptr是一个真正的指针types:

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

这可能是令人困惑的:

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

这可能不是:

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

return {}; 意味着{}返回值的初始值设定项 。 返回值是列表初始化的一个空列表。


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

对于一个按值返回的函数(即返回types不是引用而不是void ),有一个称为返回值的临时对象。 这个对象是由return语句创build的,它的初始化方法依赖于return语句中的内容。

返回值在调用函数的代码中一直存在,直到完整expression式结束。 如果它有类的types,那么它的析构函数将会运行,除非它的生命周期被调用者直接绑定了一个引用。

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

  • return some_expression; – 返回值是从some_expression 复制初始化的
  • return { possibly_empty_list }; – 返回值是从列表中初始化的列表。

假设T是函数的返回types,那么注意return T{};return {}不同:在前者中,创build了一个临时T{} ,然后从该临时中复制初始化返回值

如果T没有可访问的复制/移动构造函数,则将无法编译,但return {}; 即使这些构造函数不存在也会成功。 相应地, return T{}; 可能会显示副本构造函数等的副作用,尽pipe这是一个复制elision上下文,所以它可能不会。


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

  • 如果T是一个聚集,那么每个成员都从它的括号或等于初始值设定项进行初始化(如果有的话),否则如同{} (recursion地应用这些步骤)。
  • 如果T是具有用户提供的默认构造函数的类types,则调用该构造函数。
  • 如果T是具有隐式定义或缺省构造函数的类types,则该对象将被初始化 ,然后调用默认的构造函数。
  • 如果T是一个std::initializer_list ,则返回值是一个空的这样的列表。
  • 否则(即T是一个非类types – 返回types不能是数组),返回值是零初始化的。

对于方法返回types的新实例来说,这是一种简短的手段。