在C++11中,将非const左值引用绑定到右值是否有效?

6

我知道在c++03中,非const引用无法绑定到rvalue。

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";
  }
};

我刚刚看到了一个类似的问题:VS2010的一个bug?允许将非const引用绑定到rvalue,甚至没有警告?


4
有趣的是,很少有Objective-C或Java程序员会问关于面向语言玄学的问题,比如“将rvalue绑定到非const lvalue引用是否有效?”或者需要关注“临时引用在内部作用域结束时被销毁”的内容。只是说一下 ;) - paulsm4
你能否发布一下你是如何定义Foo的。 - diwatu
据我所知,关于Lvalue引用的绑定规则尚未改变。 - Koushik Shetty
@paulsm4:抱歉,我没时间看你的评论,我太忙了,正在等待你的垃圾回收器完成。 - Andrew Tomazos
@paulsm4 你知道吗,Objective-C并不总是有自动引用计数。在引入它之前,有很多混乱。 - JAB
2个回答

7

这个代码在C++11中能运行吗?

不行。

Foo 是自定义类,我不明白前两行为什么可以编译通过。

只有MSVC可以编译通过。MSVC有一个(可能还算有用的)编译器扩展,允许将用户定义类型的左值绑定到右值,但标准本身禁止这样做。请参见,例如,此实时示例,其中GCC 4.7.2拒绝编译您的代码。

标准对此有规定吗?

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

A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:

— If the reference is an lvalue reference and the initializer expression

— is an lvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with “cv2 T2,” or

— has a class type (i.e., T2 is a class type), where T1 is not reference-related to T2, and can be implicitly converted to an lvalue of type “cv3 T3,” where “cv1 T1” is reference-compatible with “cv3 T3” [...],

then the reference is bound to the initializer expression lvalue in the first case and to the lvalue result of the conversion in the second case (or, in either case, to the appropriate base class subobject of the object). [...]

[ ...]

Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1 shall be const), or the reference shall be an rvalue reference. [ Example:

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

—end example ]


1

不,你不能将临时对象绑定到非const左值引用。

T f();

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

这是一个安全特性。通过一个即将死亡的lvalue变异临时变量很可能是一个逻辑错误,因此语言不允许这样做。
请注意,由于RVO,实际上:
T&& t3 = f();

并且

T t3 = f();

are equivilent.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接