返回不可复制常量值的函数的不直观RVO?
考虑以下 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!?
}
该类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{});
}
这不会在 C++ <=14 中编译,但在 C++ >=17 中编译。在类可移动但不可复制的常见情况下,const这意味着在 C++14 之前无法从中获取非常量对象,但现在不再如此(只要将const其添加到纯右值中) .