C++ 可以通过C+;中的值返回局部变量+;11/14是否导致在不涉及复制/移动时,返回值由右值构造?
我知道,在以下情况下,编译器可以自由地从C++ 可以通过C+;中的值返回局部变量+;11/14是否导致在不涉及复制/移动时,返回值由右值构造?,c++,c++11,c++14,C++,C++11,C++14,我知道,在以下情况下,编译器可以自由地从makeA移动或构造返回值(但也可以自由地删除副本或移动): 我想知道的是,如果在return语句中构造A类型的对象,是否允许编译器通过右值引用从B类型的本地对象构造该类型的对象。换句话说,在下面的示例中,是否允许编译器为返回值选择A的构造函数4 struct B { }; struct A { A(A&); // (1) A(A&&); // (2) A(B&); // (3) A(B&
makeA
移动或构造返回值(但也可以自由地删除副本或移动):
我想知道的是,如果在return语句中构造A
类型的对象,是否允许编译器通过右值引用从B
类型的本地对象构造该类型的对象。换句话说,在下面的示例中,是否允许编译器为返回值选择A
的构造函数4
struct B { };
struct A {
A(A&); // (1)
A(A&&); // (2)
A(B&); // (3)
A(B&&); // (4)
};
A makeA()
{
B localB;
return localB;
}
我这样问是因为在我看来,允许在return语句中将
a
类型的本地对象视为右值的逻辑也应该允许将任何类型的本地对象视为右值,但我找不到任何这样的例子或问题。这种情况的规则在2011年到2014年之间发生了变化。编译器现在应该将localB
视为右值
return
语句的适用规则见§12.8[类副本]/p32,其内容为C++14(引用N3936,重点内容):
当满足省略复制/移动操作的条件时,但是
不适用于异常声明,并且要复制的对象是
由左值指定,或当返回中的表达式
语句是命名
对象的正文中声明了自动存储持续时间,或
最里面的封闭函数或lambda表达式的parameter declaration子句,首先执行重载解析以选择副本的构造函数,就像对象由
右值。如果第一次重载解析失败或未执行,
或者如果所选构造函数的第一个参数的类型为
不是对对象类型的右值引用(可能是cv限定),
再次执行重载解析,将对象视为
左值
添加了粗体子句,明确要求在此处调用转换移动构造函数A::A(B&&)
。这在GCC 5和Clang 3.9中实现
早在2011年,这一“try rvalue first”规则就与拷贝省略的标准密切相关(引用N3337):
当满足或将满足省略复制操作的条件时
met save,因为源对象是函数参数,
要复制的对象由左值重载指定
首先执行为副本选择构造函数的解析
好像对象是由右值指定的
由于复制省略必然要求两者具有相同的类型,因此本段不适用,编译器必须使用A::A(B&)
构造函数
请注意,由于CWG1579被认为是针对C++11的灾难恢复,编译器甚至应该在C++11模式下实现其解析 对clang和g++的快速测试表明,这两个调用#3。
localB
不是一个右值,所以不是(好吧,它可以做任何它想做的事情,只要它遵循“好像”规则,但不太可能在这里使用move。)您需要std::move(localB)
@juanchopanza不相信这是重复的-如果返回localA
和prevent RVO,您可以选择采用A&&
的构造函数。这个问题是针对返回语句的。@T.C.我不这么认为。“try rvalue first”技巧仅在“当满足或将满足省略复制操作的条件时(源对象是函数参数这一事实除外)”(C++11 12.8/32)才允许使用。我认为Jonathan Wakely的答案适用,尽管它本身并不是一个真正的副本;和A(A&&)?我使用-fno-elide构造函数编译代码,该构造函数禁用RVO。1) 它不符合省略的标准吗?2) A(A&&)来自哪里?谢谢你advance@camino1)可能存在编译器版本问题-仅在GCC主干中实现B&
部分。2) 返回的是复制初始化,因此其行为类似于A=b代码>-首先将B
转换为临时a
,并将该临时值移到返回值中。@Mikhail我使用2011/2014而不是C++11/C++14是故意的。更改是通过针对C++11的缺陷报告进行的;编译器编写者通常认为这种更改是“事实上的”C++11。@T.C.哦,我明白了。谢谢你的澄清。
struct B { };
struct A {
A(A&); // (1)
A(A&&); // (2)
A(B&); // (3)
A(B&&); // (4)
};
A makeA()
{
B localB;
return localB;
}