c++函数返回右值,但可以为其赋一个新值



代码如下:

 #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&)’

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

将右值rtByValue()传递给期望左值引用的函数不起作用,因为这将要求从右值初始化左值引用参数。§8.5.3/5描述了如何初始化左值引用& &;我就不完整引用了,它说的是左值引用可以初始化

  • 从另一个左值引用
  • 或可以转换为中间类型
  • 的左值引用的内容。
  • 或来自右值,但前提是我们初始化的左值引用是const-reference

由于需要初始化的实参不是const-reference,因此以上这些都不适用。

另一方面,
rtByValue() = aa; 

。,赋值给临时对象是可能的,因为:

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

因此,这只适用于A是类类型,并且(隐式定义的)赋值操作符是成员函数。(详情请参阅相关问题)

(因此,如果rtByValue()返回,例如,int,那么赋值将不起作用。)

因为您可以(但不应该!)重写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;
}

不编译。

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

相关内容

最新更新