"return {}" 语句在 C++11 中意味着什么?

What does "return {}" statement mean in C++11?

声明是什么

return {};

在 C++11 中指示,何时使用它而不是(比如)

return NULL;

return nullptr;

这可能令人困惑:

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

这可能不是:

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

return {};表示"return an object of the function's return type initialized with an empty list-initializer"。确切的行为取决于返回对象的类型。

来自cppreference.com(因为OP被标记为C++11,我排除了C++14和C++17中的规则;更多细节请参考link):

  • If the braced-init-list is empty and T is a class type with a default constructor, value-initialization is performed.
  • Otherwise, if T is an aggregate type, aggregate initialization is performed.
  • Otherwise, if T is a specialization of std::initializer_list, the T object is direct-initialized or copy-initialized, depending on context, from the braced-init-list.
  • Otherwise, the constructors of T are considered, in two phases:

    • All constructors that take std::initializer_list as the only argument, or as the first argument if the remaining arguments have default values, are examined, and matched by overload resolution against a single argument of type std::initializer_list
    • If the previous stage does not produce a match, all constructors of T participate in overload resolution against the set of arguments that consists of the elements of the braced-init-list, with the restriction that only non-narrowing conversions are allowed. If this stage produces an explicit constructor as the best match for a copy-list-initialization, compilation fails (note, in simple copy-initialization, explicit constructors are not considered at all).
  • Otherwise (if T is not a class type), if the braced-init-list has only one element and either T isn't a reference type or is a reference type that is compatible with the type of the element, T is direct-initialized (in direct-list-initialization) or copy-initialized (in copy-list-initialization), except that narrowing conversions are not allowed.

  • Otherwise, if T is a reference type that isn't compatible with the type of the element. (this fails if the reference is a non-const lvalue reference)
  • Otherwise, if the braced-init-list has no elements, T is value-initialized.

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

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

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

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

return NULLreturn nullptr函数时应该使用returns一个指针类型:

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
}

return {}; 表示 {}return 值 的初始值设定项。 return 值是用一个空列表进行列表初始化的。


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

对于按值 return 的函数(即 return 类型不是引用而不是 void),有一个称为 return值。该对象由 return 语句创建,其初始值设定项取决于 return 语句中的内容。

return 值一直存在到调用该函数的代码中的完整表达式结束;如果它有 class 类型,那么它的析构函数将 运行 除非调用者通过直接绑定引用来延长它的生命周期。

return 值可以用两种不同的方式初始化:

  • return some_expression; - return 值是 copy-initialized 来自 some_expression
  • return { possibly_empty_list }; - return 值为 list-initialized 来自列表。

假设 T 是函数的 return 类型,那么请注意 return T{};return {} 不同:在前者中,临时 T{} 是创建,然后 return 值 从该临时文件进行复制初始化。

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


这里是 C++14 (N4140 [dcl.init.list]/3) 中 list-initialization 的简要回顾,其中初始化器是一个空列表:

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

这是方法 return 类型的新实例的一种简写。