9

代码如下:

 #include <iostream>
 using namespace std;

 class A {

 };

 A rtByValue() {
return A();
 }

 void passByRef(A &aRef) {
    // do nothing
 }

 int main() {
    A aa;
    rtByValue() = aa;            // compile without errors
    passByRef(rtByValue());      // compile with error 

    return 0;
 }

g++ 编译器给出以下错误:

d.cpp: In function ‘int main()’:
d.cpp:19:23: error: invalid initialization of non-const reference of type ‘A&’ from an rvalue of type ‘A’
d.cpp:12:6: error: in passing argument 1 of ‘void passByRef(A&)’

它说我不能将右值作为非常量引用的参数传递,但我感到困惑的是为什么我可以分配给这个右值,正如代码所示。

4

3 回答 3

10

将右值传递rtByValue()给需要左值引用的函数不起作用,因为这需要从右值初始化左值引用参数。§8.5.3/5 描述了如何初始化左值引用——我不会完整引用它,但它基本上说可以初始化左值引用

  • 来自另一个左值引用
  • 或可以转换为中间类型的左值引用的东西
  • 或来自右值,但前提是我们初始化的左值引用是常量引用

由于我们需要初始化的参数不是 const-reference,所以这些都不适用。

另一方面,

rtByValue() = aa; 

即,分配给临时对象是可能的,因为:

(§3.10/5) 对象的左值是修改对象所必需的,但在某些情况下,类类型的右值也可用于修改其所指对象。[ 示例:为对象调用的成员函数(9.3)可以修改该对象。—结束示例]

所以这只是因为A它是类类型的,并且(隐式定义的)赋值运算符是一个成员函数。(有关详细信息,请参阅此相关问题。)

(因此,rtByValue()例如,如果要返回 an int,则分配将不起作用。)

于 2013-04-05T03:06:54.483 回答
2

因为您可以(但不应该!)覆盖 operator= 以便在右值上调用它是有意义的。考虑以下代码:

#include<iostream>

using namespace std;

class foo;

foo* gotAssigned = NULL;
int assignedto = -1;

class foo {
public:
  foo(int v) : val(v) {}
  foo& operator=(int v) {
    assignedto=v;
    gotAssigned = this;
    val = v;
    return *this;
  }
  int val;
};

foo theFoo(2);

foo returnTheFooByValue() {
  return theFoo;
}

main() {
  returnTheFooByValue()=5;
  cout << "[" << assignedto << "] " << theFoo.val << " versus " << gotAssigned->val << endl;
}

现在让我们通过几种方式编译它:

$ g++ -O0 -o rveq rveq.cc && ./rveq
[5] 2 versus 5
$ g++ -O1 -o rveq rveq.cc && ./rveq
[5] 2 versus 2
$ g++ -O4 -o rveq rveq.cc && ./rveq
[5] 2 versus -1218482176

我不能保证你会看到同样的结果。

如您所见,分配发生了,但是任何尝试使用已分配的对象都会导致特定于实现的行为。

顺便说一句,这适用于用户定义的类型。这段代码:

int v(){
  return 2;
}

main(){
  v()=4;
}

不编译。

于 2013-04-05T03:25:26.033 回答
0

@ddriver 正如我所料,这输出数字 7。

#include <iostream>
 using namespace std;

 class A {
 public:
     int i;
     A() {i = 0x07;}
 };

 A rtByValue() {
return A();
 }

 void passByRef(A &aRef) {
     cout << aRef.i;
 }

 int main() {
    passByRef(rtByValue());
    return 0;
 }
于 2013-04-05T02:16:33.937 回答