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)).)
Related
I am trying to get a better understanding of what "passing by reference" really does in c++. In the following code:
#include <iostream>
void func(int& refVar) {
std::cout << refVar;
}
int main() {
int val = 3;
func(val);
}
How does func taking in a reference change the behavior of val when func is called? Is the val variable implicitly converted to a "reference" type and then passed into the function, just like how val would be converted to a float if func took in a float instead of an int? Or is it something else?
Similarly, in this code:
int val = 3;
int& ref = val;
How is a reference of val assigned to ref? Is there implicit type conversion that can be also achieved manually using a function, or does the compiler realize without converting that ref is a reference and that it needs to store the address of val?
Why don't you just try it?
https://godbolt.org/z/8or3qfd5G
Note that the compiler could do implicit conversion and pass a reference to the temporary.
But the only (good) reason to request a reference is to either store the reference for later use or modify the value. The former would produce a dangling reference and the later would modify a value that will be deleted when the function returns and can never be accessed. So effectively this construct is just bad.
The C++ gods have therefore decided that you aren't allowed to use this. Implicit conversion produces an rvalue and you can only bind a const reference to an rvalue.
Binding a rvalue to a const reference is still dangerous. You should not store a const reference for later use because it can become dangling.
Update: I noticed I never explained how calling a function taking a reference or assigning to a reference works. It's basically both the same thing.
A reference just gives something a(nother) name. There is no type change or casting or anything involved. So when you have
`func(val)`
then for the duration of the function the value in val has a second name refVar. Same with int & refVal = val;. There now is a second name for the value in val called refVal.
Afaik they are totally interchangeable.
Note: In a function call how it works is implementation detail but most compilers pass a int * to the function under the hood.
I have the following code:
int main() {
int x = 3;
int &ref = x;
int &ref2 = ref;
ref = 100;
std::cout <<ref;
std::cout <<ref2;
return 0;
}
This print out 100 and 100. I find it confusing. My understanding was that both ref and ref2 are references to the underlying object (x=3). We then change the value of ref.
As such, I expected 100 and 3.
You don't ever change the value of ref (the language does not let you rebind a reference). In fact, this is why you need to use reference initialisation when you create a reference: you can't write int &ref; ref = x; for example.
The statement ref = 100; changes the value of the object to which the reference is bound.
Hence the output of x, ref, and ref2 are identical.
My understanding was that both ref and ref2 are references to the underlying object (x=3)
Yes.
Well, they're both references to x, whose initial value is 3.
Essentially you have a single integer object, which you can refer to by the names any of the names x, ref or ref2.
We then change the value of ref
No, you're contradicting yourself.
Objects have values. References like ref are not objects, but references to objects, and they don't have a value of their own to change.
You said that ref is a reference, which is true - it is a reference to an object of type int, which can take a value, and whose value is changed when you write ref = 100. The names x, ref and ref2 still refer to the same integer object afterwards, but now its value is 100 instead of 3.
You cannot reseat a reference (make it refer to a different object), and a reference does not have a value to change. It refers to an object, whose value may be changed via the reference.
NB. I don't think this question is quite a duplicate of Can we reassign the reference, even though it contains some of the same misunderstanding.
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
#include<vector>
#include<iostream>
using namespace std;
int main()
{
vector<int> vec = {1,2,3,4};
for(auto & it = vec.begin(); it != vec.end(); ++it)
{
cout << *it << endl;
}
}
Hello all, in C++ I use iterator by reference such as "auto & it" and the compiler return the error
" error: invalid initialization of non-const reference of type '__gnu_cxx::__normal_iterator >&' from an rvalue of type 'std::vector::iterator {aka __gnu_cxx::__normal_iterator >}'
for(auto & it = vec.begin(); it != vec.end(); ++it)
".
I know "auto it = vec.begin()" works fine but as we all know pass by reference will improve the efficiency in C++, so why this error occurs when I use "auto & it"?
so why this error occurs when I use "auto & it"?
See the return type of begin. It does not return a reference. It returns the iterator by value. Therefore the return value is a temporary in the rvalue category. Temporaries (rvalues) can not be bound to non-const lvalue references. This is what the error "invalid initialization of non-const reference of type ... from an rvalue of type ..." means.
Besides, modifying the begin pointer of the container would make little sense. It would have been silly for begin to return a reference.
Solution: Just create a copy of the iterator by declaring a non-reference value, just like you know works fine.
but as we all know pass by reference will improve the efficiency in C++
This is nonsense. An arbitrarily placed reference is unlikely to improve efficiency. Besides, you aren't trying to pass a reference here. You are trying to bind a reference to an object returned by a function.
Almost, if not always, iterators are very fast to copy (std::vector::iterator certainly is) and the indirection that you may potentially introduce with a reference may well be less efficient.
The std::vector::begin returns an rvalue (a temporary object). You cannot take a reference to a temporary object with auto& (non-const lvalue reference). If you wish to take the mentioned return value by reference, you can use auto&& instead of auto& but I don't recommend it.
Using auto&& will create a mutable rvalue reference to the return value of std::vector::begin. This will extend its lifetime but I recommend to use auto only.
Using rvalue references won't improve the efficiency of your code, the compiler will optimize out the copy/move of interator object returned from std::vector::begin by value.
auto keyword gets the type as temporary object from the expression (std::vector::begin)
since the it is temporary object and thus compiler cannot deduce to reference to it.
auto& ( non-const lvalue)
The best approach in you case to use without reference auto var instead auto &var
If you are force to use Reference
C++11 has introduced rvalue-reference, which can bind to temporary object change to && instead of & as below
vector<int> vec = {1,2,3,4};
for(auto && it = vec.begin(); it != vec.end(); ++it)
{
cout << *it << endl;
}
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.