错误: 从‘ int’类型的右值中无效初始化类型为‘ int &’的非常量引用

形式错误:

int &z = 12;

正确形式:

int y;
int &r = y;

问题 :
为什么第一个代码是错误的? 标题中的“ 意义”错误是什么?

197711 次浏览
int &z = 12;

On the right hand side, a temporary object of type int is created from the integral literal 12, but the temporary cannot be bound to non-const reference. Hence the error. It is same as:

int &z = int(12); //still same error

Why a temporary gets created? Because a reference has to refer to an object in the memory, and for an object to exist, it has to be created first. Since the object is unnamed, it is a temporary object. It has no name. From this explanation, it became pretty much clear why the second case is fine.

A temporary object can be bound to const reference, which means, you can do this:

const int &z = 12; //ok

C++11 and Rvalue Reference:

For the sake of the completeness, I would like to add that C++11 has introduced rvalue-reference, which can bind to temporary object. So in C++11, you can write this:

int && z = 12; //C+11 only

Note that there is && intead of &. Also note that const is not needed anymore, even though the object which z binds to is a temporary object created out of integral-literal 12.

Since C++11 has introduced rvalue-reference, int& is now henceforth called lvalue-reference.

References are "hidden pointers" (non-null) to things which can change (lvalues). You cannot define them to a constant. It should be a "variable" thing.

EDIT::

I am thinking of

int &x = y;

as almost equivalent of

int* __px = &y;
#define x (*__px)

where __px is a fresh name, and the #define x works only inside the block containing the declaration of x reference.

12 is a compile-time constant which can not be changed unlike the data referenced by int&. What you can do is

const int& z = 12;

C++03 3.10/1 says: "Every expression is either an lvalue or an rvalue." It's important to remember that lvalueness versus rvalueness is a property of expressions, not of objects.

Lvalues name objects that persist beyond a single expression. For example, obj , *ptr , ptr[index] , and ++x are all lvalues.

Rvalues are temporaries that evaporate at the end of the full-expression in which they live ("at the semicolon"). For example, 1729 , x + y , std::string("meow") , and x++ are all rvalues.

The address-of operator requires that its "operand shall be an lvalue". if we could take the address of one expression, the expression is an lvalue, otherwise it's an rvalue.

 &obj; //  valid
&12;  //invalid

Non-const and const reference binding follow different rules

These are the rules of the C++ language:

  • an expression consisting of a literal number (12) is a "rvalue"
  • it is not permitted to create a non-const reference with a rvalue: int &ri = 12; is ill-formed
  • it is permitted to create a const reference with a rvalue: in this case, an unnamed object is created by the compiler; this object will persist as long as the reference itself exist.

You have to understand that these are C++ rules. They just are.

It is easy to invent a different language, say C++', with slightly different rules. In C++', it would be permitted to create a non-const reference with a rvalue. There is nothing inconsistent or impossible here.

But it would allow some risky code where the programmer might not get what he intended, and C++ designers rightly decided to avoid that risk.