eiv*_*our 11 c++ return-value-optimization copy-elision c++17
考虑以下 C++ >=17 中的示例代码:
struct A{
A() = default;
A(const A&) = delete;
};
const A f(){ return A{}; }
int main(){
const A& a = f(); // OK
// A& b = f(); // Error: cannot convert 'const A' to 'A&'
const A c = f(); // OK: Copy elision
A d = f(); // OK!?
}
Run Code Online (Sandbox Code Playgroud)
该类A是不可复制的,但由于强制复制省略,我们可以将 的结果f()放入变量中。根据cppreference.com 中的这个页面,上述行为是完全合法的,因为它指定const在发生复制省略时忽略返回值上的量词。
然而,这种行为对我来说似乎非常违反直觉。由于A是不可复制的,我觉得应该没有办法const A变成A(除非你有A::A(const A&&)构造函数)。这是一个深思熟虑的决定,还是被认为是语言规范中的缺陷?
(我在尝试实现我自己的类型擦除类时遇到了这个问题。我const在函数的返回值上指定的全部目的f()是为了防止用户获得const对象的非左值引用,但这个规范似乎开个洞。)
编辑:这个例子可能更清楚地展示了反直觉:让我们考虑一个A可移动但不可复制的类。
struct A{
A() = default;
A(const A&) = delete;
A(A&&) = default;
};
int main(){
// C++14: move / C++17: copy elision
A a = A{};
// C++14: error (deleted copy constructor) / C++17: copy elision(!!)
A b = static_cast<const A>(A{});
}
Run Code Online (Sandbox Code Playgroud)
这不会在 C++ <=14 中编译,但在 C++ >=17 中编译。在类可移动但不可复制的常见情况下,const这意味着在 C++14 之前无法从中获取非常量对象,但现在不再如此(只要将const其添加到纯右值中) .
拒绝使用可移动对象进行此类初始化将是一个重大更改,因为该语言的早期版本会在那里产生移动。让它依赖于变量的cv限定将是非常微妙的。
\n对于可复制对象,新行为实际上是旧行为的子集const A:从返回值到变量的复制A可能已被省略,在这种情况下,它们与 C++17 中的对象一样。
与此同时,自 C++11 以来,const 返回值就有些不受欢迎了,因为 C++11失去了移入(按值)参数的f(return_const())能力。
C++17 对纯右值的处理(\xe2\x80\x9cm 强制复制省略\xe2\x80\x9d 是一个仅在历史上有意义的名称)还支持其他情况,例如本例中返回不可移动对象:函数被认为指定如何初始化它 \xe2\x80\x9creturns\xe2\x80\x9d 的对象,而不是实际返回完成的对象。在选择这种模型时,通常认为支持更多类型的高效代码比支持现有惯用法更重要,以防止误用。
\n| 归档时间: |
|
| 查看次数: |
187 次 |
| 最近记录: |