在 C++ 11 中将非 const 左值引用绑定到右值是不是有效?(修改)

Posted

技术标签:

【中文标题】在 C++ 11 中将非 const 左值引用绑定到右值是不是有效?(修改)【英文标题】:Is it valid to bind non-const lvalue-references to rvalues in C++ 11?(modified)在 C++ 11 中将非 const 左值引用绑定到右值是否有效?(修改) 【发布时间】:2013-05-11 03:44:24 【问题描述】:

我知道在 c++03 中,非常量引用不能绑定到右值。

T& t = getT(); 无效,在 c++11 中,我们可以这样做:T&& t = getT(); 但是上面的代码呢,在 c++11 中应该可以工作吗?

我用vs11测试了下面的代码:

 Foo getFoo() 
  return Foo();


void fz(Foo& f) 


int getInt() 
  return int();


void iz(int& i) 


int main() 
  
    Foo& z = getFoo(); //ok
    fz(getFoo()); //ok

    int& z2 = getInt(); //error: initial value of reference to non-const must be an lvalue
    iz(getInt()); //same as above
  

Foo是一个自定义类,我不明白为什么前两行编译。z引用的临时在main内部范围的末尾被破坏。标准对此有何规定?

class Foo 
public:
  Foo() 
    std::cout << "constructed\n";
  
  ~Foo() 
    std::cout << "destructed\n";
  
;

刚刚看到一个类似的问题:One VS2010 bug ? Allowing binding non-const reference to rvalue WITHOUT EVEN a warning?

【问题讨论】:

有趣的是,很少 Objective-C 或 Java 程序员会询问有关面向语言的深奥问题,例如“将右值绑定到非 const 左值引用是否有效...... ?”或者必须关心诸如“临时引用......在内部范围的末尾被破坏”之类的东西。只是说';) 你能发布你是如何定义 Foo 的吗? 绑定规则没有改变左值引用AFAIK @paulsm4:对不起,我没有时间阅读您的评论,我正忙于等待您的垃圾收集器完成。 @paulsm4 Objective-C 并不总是有自动引用计数,你知道的。在引入之前有很多混乱。 【参考方案1】:

这应该在 c++11 中工作吗?

不,不应该。

Foo是自定义类,不明白为什么前两行会编译

它只能用 MSVC 编译。 MSVC 有一个(可以说是有用的)编译器扩展,它允许将用户定义类型的左值绑定到右值,但标准本身禁止这样做。例如,请参阅this live example,其中 GCC 4.7.2 拒绝编译您的代码。

标准对此有任何说明吗?

确实如此。根据 C++11 标准的第 8.5.3/5 段:

对“cv1 T1”类型的引用由“cv2 T2”类型的表达式初始化,如下所示:

——如果引用是左值引用和初始化表达式

— 是左值(但不是位域),“cv1 T1”与“cv2 T2”引用兼容,或者

——有一个类类型(即T2是一个类类型),其中T1T2没有引用相关,并且可以是 隐式转换为“cv3 T3”类型的左值,其中“cv1 T1”与“cv3 T3”引用兼容[...],

然后引用在第一种情况下绑定到初始化表达式左值和左值结果 在第二种情况下的转换(或者,在任何一种情况下,转换为适当的基类子对象 物体)。 [...]

[...]

否则,引用应为对非易失性 const 类型的左值引用(即 cv1 应为 const),或者引用应该是一个右值引用。 [ 例子:

double& rd2 = 2.0; // error: not an lvalue and reference not const
int i = 2;
double& rd3 = i; // error: type mismatch and reference not const

——结束示例 ]

【讨论】:

【参考方案2】:

不,您不能将临时值绑定到非常量左值引用。

T f();

T& t1 = f(); // won't compile
const T& t2 = f(); // OK
T&& t3 = f(); // OK

这是一项安全功能。用一个无论如何都要死的左值来改变一个临时值很可能是一个逻辑错误,所以语言不允许这样做。

请注意,由于 RVO 比在实践中:

T&& t3 = f();

T t3 = f();

是等价的。

【讨论】:

以上是关于在 C++ 11 中将非 const 左值引用绑定到右值是不是有效?(修改)的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中将右值引用转换为临时参数到 const 左值返回的正确方法

C++ 非 const 右值参数解决方法

C++左值引用和右值引用

为啥我不能将 const 左值引用绑定到返回 T&& 的函数?

为啥非 const 引用必须用左值初始化?

非 Const 左值引用