编译器如何知道移动局部变量? [英] How does the compiler know to move local variables?

查看:109
本文介绍了编译器如何知道移动局部变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很好奇这个功能是如何工作的。考虑类似

I'm curious as to exactly how this feature works. Consider something like

std::unique_ptr<int> f() { std::unique_ptr<int> lval(nullptr); return lval; }

这个代码即使对于只移动类型也是如此,编译器隐式移动它。但在逻辑上,对于任何返回表达式,确定结果是否引用局部变量将解决暂停问题 - 如果编译器简单地将所有局部变量视为返回表达式中的rvalues,那么这将是有问题的,因为变量可以在一个表达中多次提及。即使本地只有一个 direct 引用,您也无法证明它没有其他间接别名。

This code compiles fine even for a move-only type, as the compiler implicitly moves it. But logically, for any return expression, determining whether or not the result refers to a local variable would be solving the Halting Problem- and if the compiler simply treated all local variables as rvalues in the return expression, then this would be problematic as the variable may be referred to in that one expression multiple times. Even if a local only had one direct reference, you would not be able to prove that it did not have other indirect aliases.

编译器知道何时从返回表达式移动?

So how does the compiler know when to move from the return expression?

推荐答案

有一个简单的规则:如果满足复制elision的条件(除了变量可以是函数参数),作为右值。如果失败,则视为左值。

There's a simple rule: If the conditions for copy elision are met (except that the variable may be function parameter), treat as rvalue. If that fails, treat as lvalue. Otherwise, treat as lvalue.

§12.8[class.copy] p32


当满足复制操作的删除标准时,或者除非源对象是函数参数,并且对象为复制由左值指定,重载分辨率选择用于复制的构造函数首先被执行,如同对象由右值指定。如果重载分辨率失败,或者如果所选构造函数的第一个参数的类型不是对象类型(可能是cv限定的)的右值引用,则会再次执行重载分辨率,将对象视为左值。 [注意:无论是否发生复印偏差,都必须执行此两阶段重载分辨率。如果不执行elision,则它确定要调用的构造函数,并且即使调用被省略,所选构造函数也必须可访问。 -end note ]

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. If overload resolution fails, 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. [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. —end note ]

例如:

template<class T>
T f(T v, bool b){
  T t;
  if(b)
    return t; // automatic move
  return v; // automatic move, even though it's a parameter
}

不是我个人同意因为在以下代码中没有自动移动:

Not that I personally agree with that rule, since there is no automatic move in the following code:

template<class T>
struct X{
  T v;
};

template<class T>
T f(){
  X<T> x;
  return x.v; // no automatic move, needs 'std::move'
}

a href =http://stackoverflow.com/q/9183087/500104>我的这个问题。

See also this question of mine.

这篇关于编译器如何知道移动局部变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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