"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 NULL
和return 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
是具有隐式定义或 = default
ed 默认构造函数的 class 类型,则对象为 zero-initialized 然后调用默认构造函数.
- 如果
T
是 std::initializer_list
,则 return 值是一个空的此类列表。
- 否则(即
T
是非 class 类型——return 类型不能是数组),return 值是零初始化的。
这是方法 return 类型的新实例的一种简写。
声明是什么
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 NULL
和return 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
是具有隐式定义或= default
ed 默认构造函数的 class 类型,则对象为 zero-initialized 然后调用默认构造函数. - 如果
T
是std::initializer_list
,则 return 值是一个空的此类列表。 - 否则(即
T
是非 class 类型——return 类型不能是数组),return 值是零初始化的。
这是方法 return 类型的新实例的一种简写。