Why is it allowed to pass R-Values by const refere

2020-01-27 03:41发布

问题:

as the title says why is it allowed to pass R-Values(literals) by constant reference but not normal reference

void display(const int& a)
{
cout << a ;
}

will work if called display(5) but without the const it won't work ****** I mean how can a const reference keep pointing to an R-Value (anonymous variable) ******

回答1:

For your final question:

how can a const reference keep pointing to an R-Value (anonymous variable)

Here is the answer. The C++ language says that a local const reference prolongs the lifetime of temporary values until the end of the containing scope, but saving you the cost of a copy-construction (i.e. if you were to use an local variable instead).



回答2:

Think of any object as the box containing some value inside and the box may or may not have name tag, i.e. the box with name tag as variable and the box without name tag as literal. Whether name tag is there or not, we have the box.


Reference is the way that we add name tag to our box.

int a = 5;
int &b = a;

we have two name tags for our box (with value 5 inside).

const int &c = 5;

there you are, the box was just named.


The new name of the box that has never had a name before must be marked as const. Because the value inside the box can be changed through its name, which we do not want it to happen (not allowed to happen) to our literal box.



回答3:

It gets back to the definition of literal. A literal is a constant; e.g.the value of the number 5 will not change, ever, though a variable may change from being assigned the value of 5 to another value. Passing a literal by reference implies that the function may modify it, which is something you can't do to a literal, by definition, which is why the language requires that you modify it with const. I don't think C++ could modify literals even if it let you try, but it still enforces this convention to remind the programmer that a literal value cannot be modified.

Hope that answers your question!



回答4:

Because literals are constant. 1 cannot become 2, and "abd" cannot become "edf".

If C++ allowed you to take literals by non-const reference, then it would either:

  1. Have to allow literals to change their meaning dynamically, allowing you to make 1 become 2.
  2. Expect the programmer to take extra care to modify values only via those references which do not refer to literals, and invoke undefined behaviour if you get it wrong.

(1) would create chaos in your program, because x == 1 could mean "is x equal to 2" depending on the context, and (2) is impossible to achieve because how is void display(int& a) supposed to know if it receives a literal reference or not?

Since neither of these two options makes sense, literals can only be passed by const references.


Actually, the deprecated conversion from string literals to char* is a good example of why the rules make a lot of sense, although it's not a reference but a pointer. You are allowed to let a char* point to "abc", but an attempt to actually utilise the "modifiability" attribute of the char* and modify one of the char elements results in undefined behaviour. This makes the whole deprecated conversion both dangerous and useless (in non-legacy code).

You wouldn't want to have such troubles in all other parts of the language, would you?



回答5:

An r-value is a temporary evanescent object, that can be read but is about to be destroyed. It is also a value that cannot stay on the left-hand side of an assignment (how could you make sense of assigning values to such a ghost?)

C++ has a very specific way to deal with this kind of entities. If you could pass an r-value by (non-const) reference, you could also be able to assign to it from inside the function. Therefore the rule that if r-values are to be passed by reference, this has to be a const reference.

This is not the whole truth though, because you have, indeed, r-value references (denoted with &&). So, you can, in the end, manipulate a temporary object, but you have to make an explicit statement that you really want to do so, using r-value references.