2013-10-22 42 views
1

在我看来,能够将r值引用转换为l值引用使得最终能够以临时值的形式访问临时值是没有意义的。例如:从r值ref转换为l值ref,为什么它有效?

struct S 
{ 
    int val=5; 
}; 

void foo(S &&s) 
{ 
    S &s2=s; 

    s2.val=7 
} 

void foo2(S &s2) 
{ 
    s2.val=7 
} 

int main() 
{ 
    foo(S()); // This is fine 
    foo2(S()); // Error: Even though this is logically equivalent to foo() 
} 

foo()呼叫似乎是有效的在C++或至少它用gcc 4.7.1编译。对foo2()的呼叫不是,即使这两个功能似乎在逻辑上相同。是什么赋予了?

+1

你没有转换任何东西。你将表达式's'的值绑定到引用变量's2'。没有错。 –

+0

[阅读所有关于它](http://stackoverflow.com/a/5591006/2089675) – smac89

+1

你可以直接在'foo()'内执行's.val = 7'。所以'&'和'&&'没有真正的区别,它们都可以以相同的方式使用。事实上,(设计上)很难说出它们之间的区别。最重要的区别是,当&&'是一个函数参数类型的一部分时,它允许它绑定(作为参考)临时。 –

回答

4

s已经是一个左值,就像任何其他命名变量一样。所以有一个左值引用它并不会真的改变任何东西。

右值和左值之间的关键概念区别在于,您只能访问一次右值,这样可以安全地对它进行奇怪的操作。但是,如果这一个访问将它绑定到一个右值引用,那么您就创建了一种多次访问它的方法,即将其转换为左值。所以你不能将它隐式地绑定到另一个右值引用,而你可以将它绑定到一个左值引用。

编辑:

这两件东西逻辑上等同。在一个中,你将一个右值绑定到一个左值引用。这是不允许的,因为这是误导。 (并不像允许一个左值绑定到右值引用那样危险,但仍然有误导)。通过取左值引用,foo2宣布它可能会修改传递的对象,并且这绝对是函数操作的核心部分。将临时函数传递给这样的函数没有任何意义,因为您无法观察修改。

另一方面,您将右值绑定到右值引用。 foo通过采用右值引用,宣布它可能会修改传递的对象,但这是性能优化,并不意味着被任何人观察到。传递一个临时值是有道理的,但是传递一个非临时值会是非常危险的,这就是为什么你必须在这种情况下明确表示std::move的论点。

然后,在foo中,将左值(恰好是指向右值引用类型的变量的表达式,但不相关)绑定到左值表达式。这是有道理的:你已经得到了你的右值引用变量s,它指向了一个由于已经传递给你的函数而成为你的玩物的东西。因此,如果您想将其传递给修改其状态的内容(例如foo2),然后观察更改(您可以通过ss2这两个选项),这在概念上完美无缺。

基本上,能够被观察一次或多次的东西是一个范围问题。这就是为什么“相同”的东西(它不是真的一样的东西,但你这样想)可以绑定到一个上下文中的右值引用,并在另一个上下文中绑定左值引用。

+0

我更新了我的问题,以更具体地说明为什么我感到困惑。 –

+0

规则是非const的&不允许绑定到临时对象。也许你在问“为什么用这个规则设计语言?为什么不允许非const&&绑定到临时对象?” –

+0

增加了更多细节。 –