C++ C++;nrvo/copy省略,返回语句在括号中
我在瞎搞下面的代码,使用visual studio 2017应用程序和两个不同的在线编译器得到了不同的结果。在发布模式下,VisualStudio在这两种情况下都会省略复制/移动,而这两个在线编译器只在unparenthesized return语句的情况下执行此操作。我的问题是:谁是对的,更重要的是,基本规则是什么。(我知道可以将括号与C++ C++;nrvo/copy省略,返回语句在括号中,c++,language-lawyer,copy-elision,nrvo,C++,Language Lawyer,Copy Elision,Nrvo,我在瞎搞下面的代码,使用visual studio 2017应用程序和两个不同的在线编译器得到了不同的结果。在发布模式下,VisualStudio在这两种情况下都会省略复制/移动,而这两个在线编译器只在unparenthesized return语句的情况下执行此操作。我的问题是:谁是对的,更重要的是,基本规则是什么。(我知道可以将括号与decltype(auto)语法结合使用。但这不是当前的用例) 示例代码: #include <iostream> #include <cst
decltype(auto)
语法结合使用。但这不是当前的用例)
示例代码:
#include <iostream>
#include <cstdio>
struct Foo
{
Foo() { std::cout << "default constructor" << std::endl; }
Foo(const Foo& rhs) { std::cout << "copy constructor" << std::endl; }
Foo(Foo&& rhs) { std::cout << "move constructor" << std::endl; }
Foo& operator=(const Foo& rhs) { std::cout << "copy assignment" << std::endl; return *this; }
Foo& operator=(Foo&& rhs) { std::cout << "move assignment" << std::endl; return *this; }
};
Foo foo_normal()
{
Foo a{};
return a;
}
Foo foo_parentheses()
{
Foo a{};
return (a);
}
int main()
{
auto a = foo_normal();
auto b = foo_parentheses();
std::getchar();
}
在另外两个编译器中,输出为:
default constructor
default constructor
move constructor
这是:
这种复制/移动操作的省略称为复制省略,在以下情况下是允许的(可以组合使用以消除多个副本):
(1.1)-在具有类返回类型的函数中的return语句中,当表达式是非易失性自动对象(函数参数或处理程序([except.handle])的异常声明引入的变量除外)的名称时,该对象的类型(忽略cv限定)与函数返回类型相同,通过将自动对象直接构造到函数调用的返回对象中,可以省略复制/移动操作
所以要求是
- 在具有类返回类型的函数中的
语句中,当表达式为具有相同类型(忽略cv限定)的非易失性自动对象的名称时(函数参数或处理程序([except.handle])的异常声明引入的变量除外)作为函数返回类型,可以通过将自动对象直接构造到函数调用的返回对象中来省略复制/移动操作return
return
语句中的括号表达式不符合复制省略的条件
事实上,在解析之前,
return
语句中带括号的id表达式甚至不能被视为执行移动的右值。这让我感到惊讶。我认为C++17需要复制省略,并且不允许兼容的实现打印移动构造函数
。看起来gcc理解(a)
不是对象的名称
。也许把它标记为。@Someprogrammerdude有区别,但我想在日常编程中这并不重要。例如用例附带了decltype(auto)
@nwp是的,我也很惊讶,但是对于括号表达式可能有一个特殊的(转换)规则。我现在认识到第一个编译器只是c++14。但是为什么它不符合标准呢?就因为名字在括号里?这只是一条简单的规则吗?我在某个地方读到,表达式的求值将导致左值,但我不知道这个。最后我觉得很奇怪
default constructor
default constructor
move constructor