Arq*_*ier 8 c++ rvalue language-lawyer c++11 c++17
对于函数参数,可以将 r 值绑定到 l 值常量引用。但是,这似乎不适用于特殊成员函数,如 C++11 和 C++14 中的复制构造函数和复制赋值运算符。这有什么动机吗?
使用 C++17 时,可以从 r 值复制构造,但不能复制赋值。是否有动机为什么这里只更改了复制构造函数的行为?
所有这些都在以下示例中进行了演示:
struct B {
B() = default;
B(B const&) = default;
B(B&&) = delete;
B& operator=(B const&) = default;
B& operator=(B&&) = delete;
};
void bar(B const &) {}
int main() {
bar(B{}); // does work
B(B{}); // only works in C++17
B b{};
b = B{}; // doesn't work
}
Run Code Online (Sandbox Code Playgroud)
son*_*yao 11
B(B{});
由于强制复制省略,从 C++17 开始工作省略,,完全省略移动构造;临时对象由默认构造函数直接初始化。
(强调我的)
在以下情况下,编译器需要省略类对象的复制和移动构造,即使复制/移动构造函数和析构函数具有可观察到的副作用。对象被直接构建到存储中,否则它们将被复制/移动到那里。复制/移动构造函数不需要存在或可访问:
...
在对象的初始化中,当初始化表达式是与变量类型相同类类型(忽略cv-qualification)的纯右值时:
Run Code Online (Sandbox Code Playgroud)T x = T(T(f())); // only one call to default constructor of T, to initialize x
注意:上面的规则没有指定优化:纯右值和临时值的C++17 核心语言规范与早期的 C++ 修订版根本不同:不再有临时值可以复制/移动。描述 C++17 机制的另一种方法是“非物化值传递”:返回和使用纯右值,而不会物化临时值。
在 C++17 之前,这是一种优化并且B(B{});
格式错误。
这是一种优化:即使它发生并且
/move (since C++11)
没有调用复制构造函数,它仍然必须存在且可访问(好像根本没有发生优化),否则程序是格式错误的
bar(B{});
之所以有效,是因为只有一个重载bar
将左值引用到const
,右值可以绑定到该重载;这从 C++11 开始就没有改变。
b = B{};
不起作用,因为选择了重载的移动赋值运算符;即使它被delete
明确标记为它仍然参与重载决议[1]。对于bar
如果添加超载服用右值引用作为
void bar(B&&)=delete;
Run Code Online (Sandbox Code Playgroud)
它将被选中并导致程序格式错误。
[1]请注意,对于已删除的隐式声明的移动构造函数而言,情况并非如此,重载决议会忽略这些构造函数。(C++14 起)
重载决议会忽略已删除的隐式声明的移动构造函数(否则它将阻止从右值进行复制初始化)。
归档时间: |
|
查看次数: |
225 次 |
最近记录: |