Is it ok to create references for reference variables (alias for an alias in itself ) ?
If yes, what is its application ?
In C++98, it was illegal to form references to reference types. In C++11, there are new reference collapsing rules, which means in a nutshell that a reference to a reference is still just a reference (but there are subtleties regarding lvalue and rvalue references). Consider this code:
typedef int & ir;
int a;
ir & b = a;
In C++98, the last line is illegal, since ir & is not a valid type (an attempted reference to a reference). In C++11, the references collapse and ir & is the same as int &.
Bear in mind that references are immutable, and once initialized you can never change the target of the reference. In the above code, b will always be an alias of a, and can never be changed into an alias to something else. Thus there is no need for a double indirection, as it wouldn't allow you to do anything more than what you already can do with ordinary references.
For completeness, the reference collapsing rules are as follows. Suppose T is not a reference type. Then conceptually we have:
(T&)& == T& (T&)&& == T& (T&&)& == T& (T&&)&& == T&&
You can't create a reference to a reference, and C++ has no reference-to-reference types.
If you use a reference to initialize another reference, for example:
int i = 1;
int &a = i;
int &b = a;
Then what you've actually done is bound the referand of a to b. a is a name for the same object that i is a name for, and consequently int &b = a; has exactly the same effect as int &b = i;. So you have two references to the same object, i.
I can't immediately think of a reason to have two references in the same function, but you'd commonly create multiple references if you have a function f that takes a reference parameter, and passes this on to another function g that also takes a reference parameter. Then f and g each has a reference to the same object.
In Python, like this:
a = 1
b = a
after this processing, the id for "a" and "b" is the same one.
Related
why this binding is ok
int main()
{
double d = 4.56;
const int &r = d;
return 0;
}
but this is not
int main()
{
double d = 4.56;
int &r = d;
return 0;
}
can anyone explain me while the first one compile but second one shows error
When you bind to a converted type (the double has to be converted to an int), you get a prvalue, since the converted int is a temporary with no address in memory. Therefore, binding a regular reference to it doesn't work, because they can only bind to glvalues. const type references can bind to prvalues, so the first one compiles still. Source: https://en.cppreference.com/w/cpp/language/value_category
An int reference cannot be bound to an object of type double, because the types mismatch.
So in order to make the initialization of the reference work at all, a new temporary object of the correct type int must be created. This is possible because there is an implicit conversion sequence from double to int.
The reference should then bind to this temporary, i.e. to a rvalue expression, but only const lvalue references are allowed to bind to rvalues. Non-const lvalue references are not allowed to do that, making the second program ill-formed.
Note that in the first program, although the reference is bound to a temporary object that would usually be destroyed at the end of the full-expression that it was created in, binding to a reference extends the lifetime of that temporary object to the lifetime of the reference. So using r in the first program is actually ok.
However, access through r will not refer to d, but to that new temporary object that is independent of d, which may be surprising, and therefore I think it is not a good idea to write like that. Use auto& or const auto& to make sure that r will certainly refer to d and that there is never any implicit conversion happening due to a type mismatch. If you want the conversion, just use int instead of a reference to int.
int main()
{
int n = 1;
int* const p = &n; // ok
*p = 2; // ok as expected.
p = 0; // error as expected.
int& const m = n;
// error: 'const' qualifier may not be
// applied to a reference
return 0;
}
Why no const reference in C++ just like const pointer?
What's the rationale behind the design?
References in C++ differ from pointers in several essential ways. One of the difference is:
Once a reference is created, it cannot be later made to reference another object; it cannot be reseated. This is often done with pointers.
It means Reference are like similar (see the link at the end of this answer) to const pointer (not pointer to a const!) in C++...
int a = 5;
int& m = a; // Behaves similar to int * const m = &a;
// See the link at the bottom for the differences between const pointer and reference.
and hence, you can't change/rebind them to point to some other address. So, you don't need a explicit const qualifier for a reference and that's why it is disallowed by the compiler.
See this link to learn Why are references not reseatable in C++?. I have copied the accepted answer of the above link:
The reason that C++ does not allow you to rebind references is given in Stroustrup's "Design and Evolution of C++" :
It is not possible to change what a reference refers to after initialization. That is, once a C++ reference is initialized it cannot be made to refer to a different object later; it cannot be re-bound. I had in the past been bitten by Algol68 references where r1=r2 can either assign through r1 to the object referred to or assign a new reference value to r1 (re-binding r1) depending on the type of r2. I wanted to avoid such problems in C++.
EDIT:
See this link for Difference between const pointer and reference? (Thanks to #M.M for pointing out the ambiguity in my statement).
Why no const reference in C++ just like const pointer?
References cannot be modified. Adding const qualification to non-modifiable entity would be meaningless and confusing.
Note that it is technically possible to apply const to a reference indirectly through a type alias or template type argument. Example:
T some_t;
using Ref = T&;
Ref const some_ref = some_t; // well-formed
Ref const type "collapses" into T&, and is same as unqualified Ref. I recommend to generally avoid creating type aliases for pointers and references, except for rare cases where they are conventional. Specifically, Container::reference type alias and similar are conventional.
int& const m = n;
IMHO because it's inherently constant by compiler nature, just
int n ;
n has ininherent constant reference
so as it is parsing codes it just determine to whichever place const qualifier is only allowed being there, by a compiler rule method for parsing, if not allowed then go to error/warning
In http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/ it mentions "most important const" where by C++ deliberately specifies that binding a temporary object to a reference to const on the stack lengthens the lifetime of the temporary to the lifetime of the reference itself. I was wondering why c++ only allows the lifetime of the object to be lengthened when the reference is const and not when it isn't? What is the rational behind the feature and why does it have to be const?
Here's an example:
void square(int &x)
{
x = x * x;
}
int main()
{
float f = 3.0f;
square(f);
std::cout << f << '\n';
}
If temporaries could bind to non-const lvalue references, the above would happily compile, but produce rather surprising results (an output of 3 instead of 9).
Consider the following:
int& x = 5;
x = 6;
What should happen if this was allowed? By contrast, if you did
const int& x = 5;
there would be no legal way to modify x.
Note that const references can be bound to objects that don't even have an address normally. A const int & function parameter can take an argument formed by the literal constant expression 42. We cannot take the address of 42, so we cannot pass it to a function that takes a const int *.
const references are specially "blessed" to be able to bind to rvalues such as this.
Of course, for traditional rvalues like 2 + 2, lifetime isn't an issue. It's an issue for rvalues of class type.
If the binding of a reference is allowed to some object which, unlike 42, does not have a pervasive lifetime, that lifetime has to be extended, so that the reference remains sane throughout its scope.
It's not that the const causes a lifetime extension, it's that a non-const reference is not allowed. If that were allowed, it would also require a lifetime extension; there is no point in allowing some reference which then goes bad in some parts of its scope. That behavior undermines the concept that a reference is safer than a pointer.
Today I came to know that references are not reseatable
Consider the code:
map<int,int> z;
z.insert(make_pair(1,2));
z.insert(make_pair(3,5));
z.insert(make_pair(4,6));
auto ref = z.at(1);
ref = z.at(3);
std::map::at returns a reference to the mapped value of the requested element, implies ref is a reference. Why is it allowed to be reassigned(as references cannot be re-binded). What is happening here.
auto doesn't make reference types. The expression z.at(1) is an lvalue of type int, so ref is also an int.
(If you wanted a reference, you'd have to say auto & or auto && (or in C++14 decltype(auto)).)
Wrong form:
int &z = 12;
Correct form:
int y;
int &r = y;
Question:
Why is the first code wrong? What is the "meaning" of the error in the title?
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
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.
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;
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.
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.