返回带有已删除移动/复制 ctor 的类型临时
Returning temporaries of type with deleted move/copy ctor
请考虑以下程序:
#include<iostream>
using namespace std;
struct S
{
S() = default;
S(const S& other) = delete;
S(S&& other) = delete;
int i;
};
S nakedBrace()
{
return {}; // no S constructed here?
}
S typedBrace()
{
return S{};
}
int main()
{
// produce an observable effect.
cout << nakedBrace().i << endl; // ok
cout << typedBrace().i << endl; // error: deleted move ctor
}
示例会话:
$ g++ -Wall -std=c++14 -o no-copy-ctor no-copy-ctor.cpp
no-copy-ctor.cpp: In function 'S typedBrace()':
no-copy-ctor.cpp:19:12: error: use of deleted function 'S::S(S&&)'
return S{};
^
no-copy-ctor.cpp:8:5: note: declared here
S(S&& other) = delete;
令我惊讶的是,gcc 接受了nakedBrace()
.我认为从概念上讲,这两个函数是等效的:构造并返回临时S
。可以执行也可能不执行复制,但根据标准 (12.8/32) 的规定,移动或复制 ctor(此处删除两者)仍必须可访问。
这是否意味着nakedBrace()
永远不会构造 S?或者确实如此,但直接在带有大括号初始化的返回值中,因此在概念上不需要复制移动/ctor?
标准行为。
N4140 [stmt.return]/2:
[...]带有大括号初始化列表的 return 语句初始化对象 或通过指定初始值设定项的复制列表初始化 (8.5.4) 从函数返回的引用 列表。[...]
这意味着 nakedBrace
和 typedBrace
执行的初始化等效于以下内容:
S nakedBrace = {}; //calls default constructor
S typedBrace = S{}; //calls default, then copy constructor (likely elided)
[标准返回]/2 ...具有非 void 类型表达式的 return 语句只能在返回值的函数中使用;表达式的值将返回给函数的调用方。表达式的值隐式转换为它所在的函数的返回类型。返回语句可能涉及临时对象的构造和复制或移动 (12.2)...带有大括号 init-list 的 return 语句通过指定初始值设定项列表中的复制列表初始化 (8.5.4) 来初始化要从函数返回的对象或引用。
[class.temporary]/1 类类型的临时是在各种上下文中创建的:...返回一个 prvalue (6.6.3) ...
所以是的,据我所知,存在语义差异。 typedBrace
计算表达式S{}
,生成类型为 S
的 prvalue,然后尝试从该表达式复制构造其返回值。 相反,nakedBrace
直接从大括号初始化列表中构造其返回值。
这与S s{};
(有效)与S s = S{};
(不起作用)的情况相同,只是被某种程度的间接性所掩盖。
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 为什么 std::optional::value_or 没有默认 ctor 类型的专用化?
- 为什么在 ctor 的参数列表中将成员"x"的类型替换为"decltype(x)"会破坏类模板参数推导?
- 模板 ctor 类型推导不起作用(没有匹配的构造函数用于初始化 ...)与函数<>参数
- 初始化在类类型 #define 中定义的非静态成员数组,不带默认 ctor
- 如果每个参数都可以转换为特定类型,则启用 ctor
- C++错误 C2533,ctor :构造函数不允许返回类型
- 当使用类型为"类&&"的变量作为参数时,为什么调用复制 ctor 而不是移动 ctor
- 使用大括号初始化列表或传统的 ctor 语法实例化类型
- 返回带有已删除移动/复制 ctor 的类型临时
- c++ 11: bind std::sort用于用户定义的类型,然后使用该绑定作为ctor的参数
- 为什么"std::p air"将"std::tuple"作为ctor参数类型而不是"const std::tuple&"?
- 为什么分配器类型作为模板参数而不是 ctor 的参数?
- 指针类型的CTOR需要显式吗?
- 为什么VS2010向导在ctor和dtor中添加void类型