在c++ 11中“返回{}”语句意味着什么?

时间:2022-06-17 21:05:44

What does the statement

什么声明

return {};

in C++11 indicate, and when to use it instead of (say)

在c++ 11中,表示何时使用而不是(比如说)

return NULL;

or

return nullptr;

4 个解决方案

#1


93  

return {}; indicates "return an object of the function's return type initialized with an empty list-initializer". The exact behaviour depends on the returned object's type.

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

From cppreference.com (because the OP is tagged C++11, I excluded the rules in C++14 and C++17; refer to the link for further details):

在cppreference.com(因为OP被标记为c++ 11,所以我排除了c++ 14和c++ 17中的规则;详情请参阅连结:

  • If the braced-init-list is empty and T is a class type with a default constructor, value-initialization is performed.
  • 如果括号内列表为空,T是具有默认构造函数的类类型,则执行值初始化。
  • Otherwise, if T is an aggregate type, aggregate initialization is performed.
  • 否则,如果T是一个聚合类型,则执行聚合初始化。
  • 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.
  • 否则,如果T是std:: initizerali_list的专门化,则根据上下文,T对象将直接初始化或复制初始化,从括在列表中。
  • Otherwise, the constructors of T are considered, in two phases:

    否则,将T的构造函数分为两个阶段:

    • 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
    • 所有将std::initializer_list作为唯一参数的构造函数,或者作为第一个参数(如果其余的参数具有默认值)的构造函数都将被检查,并通过对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).
    • 如果前一阶段没有产生匹配,则T的所有构造函数都参与对由括在括号内的列表中的元素组成的一组参数的重载解析,并限制只允许非收缩转换。如果此阶段生成一个显式构造函数作为复制-列表-初始化的最佳匹配,则编译将失败(注意,在简单的复制-初始化中,根本不考虑显式构造函数)。
  • 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.

    否则(如果T不是一个类类型),如果braced-init-list只有一个元素和T不是引用类型或者是一个引用类型,是兼容的类型元素,T是direct-initialized(direct-list-initialization)或copy-initialized(copy-list-initialization),除了缩小转换是不允许的。

  • 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)
  • 否则,如果T是与元素类型不兼容的引用类型。(如果引用是非const lvalue引用,则失败)
  • Otherwise, if the braced-init-list has no elements, T is value-initialized.
  • 否则,如果括号内的列表没有元素,则T是值初始化的。

Before C++11, for a function returning a std::string, you would have written:

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

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

Using the brace syntax in C++11, you don't need to repeat the type:

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

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

return NULL and return nullptr should be used when the function returns a pointer type:

当函数返回指针类型时,应该使用返回NULL和return nullptr:

any_type* get_pointer() {
    return nullptr;
}

However, NULL is deprecated since C++11 because it is just an alias to an integer value (0), while nullptr is a real pointer type:

但是,由于c++ 11只是一个整数值(0)的别名,所以NULL被弃用,而nullptr是一个真正的指针类型:

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

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

#2


87  

This is probably confusing:

这可能是令人困惑:

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

This is probably not:

这可能不是:

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

#3


24  

return {}; means that {} is the initializer for the return value. The return value is list-initialized with an empty list.

返回{ };表示{}是返回值的初始化器。返回值用空列表初始化。


Here is some background on the return value, based on [stmt.return] in the C++ Standard:

这里是基于[stmt]的返回值的一些背景。在c++标准中:

For a function that returns by value (i.e. the return type is not a reference and not void), there is a temporary object called the return value. This object is created by the return statement, and its initializers depend on what was in the return statement.

对于按值返回的函数(即返回类型不是引用,也不是void),有一个名为返回值的临时对象。该对象由return语句创建,其初始化器依赖于return语句中的内容。

The return value survives until the end of the full-expression in the code that called the function; if it has class type, then its destructor will run unless it has lifetime extended by the caller binding a reference directly to it.

返回值一直保存到调用函数的代码中的完整表达式的末尾;如果它有类类型,那么它的析构函数将运行,除非调用者将引用直接绑定到它,从而扩展它的生存期。

The return value can be initialized in two different ways:

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

  • return some_expression; - the return value is copy-initialized from some_expression
  • 返回some_expression;-返回值是从some_expression复制初始化的
  • return { possibly_empty_list }; - the return value is list-initialized from the list.
  • 返回{ possibly_empty_list };-返回值从列表中初始化。

Assuming T is the function's return type, then note that return T{}; is different to return {}: in the former, a temporary T{} is created, and then the return value is copy-initialized from that temporary.

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

This will fail to compile if T has no accessible copy/move-constructor, but return {}; will succeed even if those constructors are not present. Accordingly, return T{}; may show side-effects of the copy-constructor etc., although this is a copy elision context so it may not.

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


Here's a brief recap of list-initialization in C++14 (N4140 [dcl.init.list]/3), where the initializer is an empty list:

下面是c++ 14 (N4140 [dcl.init.list]/3)中的列表初始化的简要概述,其中初始化器是一个空列表:

  • If T is an aggregate, then each member is initialized from its brace-or-equal-initializer if it had one, otherwise as if by {} (so apply these steps recursively).
  • 如果T是一个集合,那么每个成员都从它的brace-or-equal-initializer(如果它有的话)初始化,否则就像用{}(所以递归地应用这些步骤)一样。
  • If T is a class type with a user-provided default constructor, that constructor is called.
  • 如果T是具有用户提供的默认构造函数的类类型,则调用该构造函数。
  • If T is a class type with an implicitly-defined, or = defaulted default constructor, the object is zero-initialized and then the default constructor is called.
  • 如果T是一个具有隐含定义的类类型,或= defaultdefault构造函数的类类型,则对象是零初始化的,然后调用默认构造函数。
  • If T is a std::initializer_list, the return value is an empty such list.
  • 如果T是std::initializer_list,返回值是一个空的此类列表。
  • Otherwise (i.e. T is a non-class type -- return types cannot be arrays), the return value is zero-initialized.
  • 否则(即T是非类类型——返回类型不能是数组),返回值为零初始化。

#4


3  

It's a sort of short hand for a new instance of the methods return type.

对于方法返回类型的新实例来说,这是一种简短的处理。

#1


93  

return {}; indicates "return an object of the function's return type initialized with an empty list-initializer". The exact behaviour depends on the returned object's type.

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

From cppreference.com (because the OP is tagged C++11, I excluded the rules in C++14 and C++17; refer to the link for further details):

在cppreference.com(因为OP被标记为c++ 11,所以我排除了c++ 14和c++ 17中的规则;详情请参阅连结:

  • If the braced-init-list is empty and T is a class type with a default constructor, value-initialization is performed.
  • 如果括号内列表为空,T是具有默认构造函数的类类型,则执行值初始化。
  • Otherwise, if T is an aggregate type, aggregate initialization is performed.
  • 否则,如果T是一个聚合类型,则执行聚合初始化。
  • 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.
  • 否则,如果T是std:: initizerali_list的专门化,则根据上下文,T对象将直接初始化或复制初始化,从括在列表中。
  • Otherwise, the constructors of T are considered, in two phases:

    否则,将T的构造函数分为两个阶段:

    • 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
    • 所有将std::initializer_list作为唯一参数的构造函数,或者作为第一个参数(如果其余的参数具有默认值)的构造函数都将被检查,并通过对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).
    • 如果前一阶段没有产生匹配,则T的所有构造函数都参与对由括在括号内的列表中的元素组成的一组参数的重载解析,并限制只允许非收缩转换。如果此阶段生成一个显式构造函数作为复制-列表-初始化的最佳匹配,则编译将失败(注意,在简单的复制-初始化中,根本不考虑显式构造函数)。
  • 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.

    否则(如果T不是一个类类型),如果braced-init-list只有一个元素和T不是引用类型或者是一个引用类型,是兼容的类型元素,T是direct-initialized(direct-list-initialization)或copy-initialized(copy-list-initialization),除了缩小转换是不允许的。

  • 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)
  • 否则,如果T是与元素类型不兼容的引用类型。(如果引用是非const lvalue引用,则失败)
  • Otherwise, if the braced-init-list has no elements, T is value-initialized.
  • 否则,如果括号内的列表没有元素,则T是值初始化的。

Before C++11, for a function returning a std::string, you would have written:

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

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

Using the brace syntax in C++11, you don't need to repeat the type:

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

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

return NULL and return nullptr should be used when the function returns a pointer type:

当函数返回指针类型时,应该使用返回NULL和return nullptr:

any_type* get_pointer() {
    return nullptr;
}

However, NULL is deprecated since C++11 because it is just an alias to an integer value (0), while nullptr is a real pointer type:

但是,由于c++ 11只是一个整数值(0)的别名,所以NULL被弃用,而nullptr是一个真正的指针类型:

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

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

#2


87  

This is probably confusing:

这可能是令人困惑:

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

This is probably not:

这可能不是:

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

#3


24  

return {}; means that {} is the initializer for the return value. The return value is list-initialized with an empty list.

返回{ };表示{}是返回值的初始化器。返回值用空列表初始化。


Here is some background on the return value, based on [stmt.return] in the C++ Standard:

这里是基于[stmt]的返回值的一些背景。在c++标准中:

For a function that returns by value (i.e. the return type is not a reference and not void), there is a temporary object called the return value. This object is created by the return statement, and its initializers depend on what was in the return statement.

对于按值返回的函数(即返回类型不是引用,也不是void),有一个名为返回值的临时对象。该对象由return语句创建,其初始化器依赖于return语句中的内容。

The return value survives until the end of the full-expression in the code that called the function; if it has class type, then its destructor will run unless it has lifetime extended by the caller binding a reference directly to it.

返回值一直保存到调用函数的代码中的完整表达式的末尾;如果它有类类型,那么它的析构函数将运行,除非调用者将引用直接绑定到它,从而扩展它的生存期。

The return value can be initialized in two different ways:

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

  • return some_expression; - the return value is copy-initialized from some_expression
  • 返回some_expression;-返回值是从some_expression复制初始化的
  • return { possibly_empty_list }; - the return value is list-initialized from the list.
  • 返回{ possibly_empty_list };-返回值从列表中初始化。

Assuming T is the function's return type, then note that return T{}; is different to return {}: in the former, a temporary T{} is created, and then the return value is copy-initialized from that temporary.

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

This will fail to compile if T has no accessible copy/move-constructor, but return {}; will succeed even if those constructors are not present. Accordingly, return T{}; may show side-effects of the copy-constructor etc., although this is a copy elision context so it may not.

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


Here's a brief recap of list-initialization in C++14 (N4140 [dcl.init.list]/3), where the initializer is an empty list:

下面是c++ 14 (N4140 [dcl.init.list]/3)中的列表初始化的简要概述,其中初始化器是一个空列表:

  • If T is an aggregate, then each member is initialized from its brace-or-equal-initializer if it had one, otherwise as if by {} (so apply these steps recursively).
  • 如果T是一个集合,那么每个成员都从它的brace-or-equal-initializer(如果它有的话)初始化,否则就像用{}(所以递归地应用这些步骤)一样。
  • If T is a class type with a user-provided default constructor, that constructor is called.
  • 如果T是具有用户提供的默认构造函数的类类型,则调用该构造函数。
  • If T is a class type with an implicitly-defined, or = defaulted default constructor, the object is zero-initialized and then the default constructor is called.
  • 如果T是一个具有隐含定义的类类型,或= defaultdefault构造函数的类类型,则对象是零初始化的,然后调用默认构造函数。
  • If T is a std::initializer_list, the return value is an empty such list.
  • 如果T是std::initializer_list,返回值是一个空的此类列表。
  • Otherwise (i.e. T is a non-class type -- return types cannot be arrays), the return value is zero-initialized.
  • 否则(即T是非类类型——返回类型不能是数组),返回值为零初始化。

#4


3  

It's a sort of short hand for a new instance of the methods return type.

对于方法返回类型的新实例来说,这是一种简短的处理。