可以通过C ++ 11/14中的值返回一个局部变量导致在没有复制/移动时由rvalue构造的返回值? [英] Can returning a local variable by value in C++11/14 result in the return value being constructed by rvalue when no copy/move is involved?

查看:140
本文介绍了可以通过C ++ 11/14中的值返回一个局部变量导致在没有复制/移动时由rvalue构造的返回值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道在以下情况下,编译器可以自由移动 - 从 makeA (但是也可以免费复制或移动) :

  struct A 
{
A(A&);
A(A&&);
};

makeA()
{
A localA;
return localA;
}

我不知道是否允许编译器构造一个类型如果在return语句中构造,通过右值引用从 B 类型的本地对象返回一个。换句话说,在下面的例子中,编译器是否允许为返回值选择 A 的构造函数4?

  struct B {}; 
struct A {
A(A&); //(1)
A(A&&&;); //(2)
A(B&); //(3)
A(B&&&;); //(4)
};

makeA()
{
B localB;
return localB
}

我问这是因为在我看来,在返回语句中被视为一个右值的类型的局部对象也应该允许任何类型的局部被视为右值,但是我找不到任何例子或者

解决方案

这种情况的规则在2011年和2014年之间改变。编译器现在应该处理 localB 作为右值。



找到 return 语句的适用规则在§12.8[class.copy] / p32,它读取C ++ 14(引用N3936,强调我):


满足复制/移动操作的精度的标准,但
不是用于异常声明,并且要复制的对象是由左值指定的
,或当返回
语句中的表达式是一个(可能加括号的) id-expression ,它命名一个在主体中声明的具有自动存储持续时间的
对象或
<最里面的封闭函数或 lambda-expression
的重写分辨率,首先执行选择复制的构造函数的重载分辨率,如同指定对象由
右值。如果第一个重载解析失败或者没有执行,
或者如果所选构造函数的第一个参数的类型是
,而不是对象类型的一个右值引用(可能是cv限定的),$ b $ =http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1579> CWG问题1579 ,明确要求转换移动构造函数 A :: A(B&&)。 (不幸的是,目前没有太多的编译器支持这个。在我测试的编译器,这只是在中继版本的GCC实现。)

回到2011年,这个try rvalue first规则与复制删除标准密切相关(引用N3337):


操作被满足或者将
满足保存,因为源对象是函数参数
并且要复制的对象由lvalue指定,重载
分辨率以选择构造函数


由于复制elision必须要求两个具有相同的类型,本段不适用,编译器必须使用 A :: A(B&)构造函数。



请注意,由于CWG 1579被认为是针对C ++ 11的DR,编译器应该在C ++ 11模式下实现其分辨率。 GCC干线这样做。


I know that in the following situation that the compiler is free to move-construct the return value from makeA (but is also free to elide the copy or move altogether):

struct A
{
    A(A&);
    A(A&&);
};

A makeA()
{
    A localA;
    return localA;
}

What I wonder is whether the compiler is allowed to construct an object of type A from a local object of type B by rvalue reference if it is being constructed in the return statement. In other words, in the following example, is the compiler allowed to select A's constructor 4 for the return value?

struct B { };
struct A {
    A(A&);  // (1)
    A(A&&); // (2)
    A(B&);  // (3)
    A(B&&); // (4)
};

A makeA()
{
    B localB;
    return localB;
}

I ask this because it would seem to me that the same logic that allows a local object of type A to be treated as an rvalue in the return statement should also allow a local of any type to be treated as an rvalue, but I cannot find any examples or questions of this nature.

解决方案

The rule for this situation changed between 2011 and 2014. The compiler should now treat localB as an rvalue.

The applicable rule for return statements is found in §12.8 [class.copy]/p32, which reads in C++14 (quoting N3936, emphasis mine):

When the criteria for elision of a copy/move operation are met, but not for an exception-declaration, and the object to be copied is designated by an lvalue, or when the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If the first overload resolution fails or was not performed, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.

The bolded clause was added by CWG issue 1579, expressly to require the converting move constructor A::A(B&&) to be called here. (Unfortunately, currently there's not much compiler support for this. Of the compilers I tested, this is only implemented in the trunk version of GCC.)

Back in 2011, this "try rvalue first" rule was closely tied to the criteria for copy elision (quoting N3337):

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.

Since copy elision necessarily requires the two to have the same type, this paragraph didn't apply, and the compiler had to use the A::A(B&) constructor.

Note that as CWG 1579 is considered a DR against C++11, compilers should implement its resolution even in C++11 mode. GCC trunk does so.

这篇关于可以通过C ++ 11/14中的值返回一个局部变量导致在没有复制/移动时由rvalue构造的返回值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆