I'm wondering why returning const reference of a local object is illegal whereas returning a local object is legal as long as you assign it to a const reference?
vector<int> f_legal() {
vector<int> tempVec;
tempVec.push_back(1);
return tempVec;
}
const vector<int>& f_illegal() {
vector<int> tempVec;
tempVec.push_back(1);
return tempVec;
}
void g() {
const vector<int>& v1 = f_legal(); // legal
const vector<int>& v2 = f_illegal(); // illegal
}
Edit:
My point is that if assigning a const ref to a returned local variable is legal, then shouldn't assigning a const ref to a returned const ref of a local variable be legal as well?
Returning a reference to a local variable is illegal (Undefined Behavior). Period. There is no const or mutable clause.
This is because local function variables have automatic storage duration. They are "destroyed" after the function exits. If the function returns a reference to such a variable, that reference it is said to be dangling: it refers to an object that no longer exists.
The first one is legal because of a special C++ rule: initializing a reference to a prvalue extends the lifetime of that temporary object to the lifetime of the reference.
Even if you assign it to a const reference, the return value is declared as passed by value, that means it'll be copied[1] to outside as a temporary object, and then binded to the const reference. Binding temporary object to a const reference is fine, the object won't be destroyed until getting out of the lifetime of the const reference.
On the other hand, returning reference of a local variable is illegel. The local variable'll be destroyed when the function returned, that means the outside reference will be dangled.
EDIT
My point is that if assigning a const ref to a returned local variable is legal, then shouldn't assigning a const ref to a returned const ref of a local variable be legal as well?
The point is the 1st case is not assigning a const ref to a returned local variable, it's assigning a const ref to a returned temporary variable. (Which might copied from the local variable.)
[1] The copy might be omitted according to RVO technically.
Most likely because it would totally ruin the whole stack based calling conventions that have served us well for decades...that pretty much every CPU assumes.
Related
Is the following UB (undefined-behavior) ?
Is it really one level "too much" that value is now dangling and there is no lifetime extension done by the compiler/language rules?
const int &get_value(const int &value) { return value; };
int main()
{
const auto &value = get_value(5);
printf("Value is: %d", value);
}
Yes, this is UB. When passing by 5 to get_value(), a temporary object is created and function parameter const reference value bind to it. Since, the temporary object bound to function parameter value, it will persist until the completion of the full expression containing the call. In the main(), you are dereferencing a reference which is not bound to a living object and this is undefined bahavior.
In C++ when you have the following:
std::string get_string();
std::string const& v = get_string();
The lifetime of the temporary returned from get_string() is extended for the same lifetime of the reference v;
If I have the following:
std::string const& get_string(std::string const& p) {
return p;
}
std::string const& v =
get_string(std::string{"Hello"});
Is the lifetime of the temporary extended? or is this a dangling reference;
My understanding is that the temporary is bound to the lifetime of p
and that only exists for the duration of the function and that secondary references to the temporary dont extend the lifetime.
What is the expected result?
Yes, the lifetime of the temporary is not extended further more; after the full expression the reference v becomes dangled.
std::string const& v = get_string(std::string{"Hello"});
// v becomes dangled now
My understanding is that the temporary is bound to the lifetime of p and that only exists for the duration of the function
To be precisely, the temporary exists until the end of the full expression, not only the duration of the function.
a temporary bound to a reference parameter in a function call exists until the end of the full expression containing that function call: if the function returns a reference, which outlives the full expression, it becomes a dangling reference.
In general, the lifetime of a temporary cannot be further extended by "passing it on": a second reference, initialized from the reference to which the temporary was bound, does not affect its lifetime.
That means something like auto sz = get_string(std::string{"Hello"}).size(); is fine.
What is the purpose for the "const" keyword for a reference if the object it is referencing is not a const object? Is there any difference between what r1 and r2 does (below)?
int i = 42; // non const object
const int &r1 = i; // const reference to non const object
int j = 25; // non const object
int &r2 = j; // non const reference to non const object
Here's a quote from CPP Primer 5th:
"C++ programmers tend to abbreviate the phrase “reference to const” as
“const reference.” This abbreviation makes sense—if you remember that it
is an abbreviation.
Technically speaking, there are no const references. A reference is not an
object, so we cannot make a reference itself const. Indeed, because there
is no way to make a reference refer to a different object, in some sense all
references are const. Whether a reference refers to a const or nonconst
type affects what we can do with that reference, not whether we can alter
the binding of the reference itself."
I think this means that making a reference a "const" when it is referenced to a non const object does absolutely nothing. We may as well take that const keyword out when defining that reference.
Asking this question here for confirmation.
Edit: Looks like my initial conjecture is wrong. I understand now that a const reference to a non const object does have a purpose: to prevent the reference from modifying the object. The non const object can still be modified by other means but not by this const reference.
Thanks all.
"What is the purpose for the "const" keyword for a reference if the object it is referencing is not a const object?"
The purpose is to prevent that reference being used to modify the object it is referencing.
int i = 42; // non const object
const int &r1 = i; // const reference to non const object
r1 = 6 * 9; // error, r1 cannot be used to modify i;
To understand it better you can look into difference between const pointer and pointer to a const data:
int i, j;
const int *p1 = &i; // pointer to constant int
int *const p2 = &i; // constant pointer to int
*p1 = 0; // error, p1 points to const int
*p2 = 0; // it is fine sets i to 0
p1 = &j; // fine p1 now points to anbother int
p2 = &j; // error, p2 is a constant pointer
so now if we replace pointer to reference we can see similar things, except reference by itself is not changeable ie you cannot make reference to refer to another object after it is created (unlike non constant pointer) and any reference is like constant pointer. So const reference in this meaning does not make any sense and usually by const reference people mean reference to a const type. That what quote from primer means.
As for difference in your code, yes there is difference - you cannot change object through const reference does not matter if that reference points to const object or not.
There's a useful way to figure out what constness means in pointers and references, which is to read the declaration from right to left (see these answers). So const int &r1 can be read as "r1 is a reference to an int const".
Basically, r1 refers to an int which cannot be modified. This means that the referred-to int is either a const int, or it's a simple int. The binding of a const const reference to a non-const object (for example, when writing something like int i = 5; const int& r = i;) is perfectly legal because there's nothing wrong with not modifying a non-const object.
I think this means that making a reference a "const" when it is referenced to a non const object does absolutely nothing. We may as well take that const keyword out when defining that reference.
Not true.
You may not modify the a non-const object through a const reference.
You may modify a non-const object through a non-const reference.
Unless an object is created in the read-only section of a program, it is open for modifiction without adverse consequences. However, when you use a const reference to a non-const object, you are asking the compiler to not let you modify the object through that particular reference. It does not mean that you will not modify object.
It's similar to function arguments. When a function uses a const reference argument type, the function is promising to you that it will not modify the object. It does not mean that the object is not modifiable at all.
If we use const with variable then its value can not be change and when it is used with const reference then its reference can not be changed if we used it with object then whole data is used in object it can not be changed.
It's also worth to mention the behavior when you pass both to a function call
fun1(const int& R1) vs. fun2(int & R1)
In fun1 you may call it with either cost or variable, for example fun1(5) or fun1(var1); assuming int var1=5;
In fun2, you simply can't call it with const, fun2(5) will give you compiler error, which means in that case you've to add another overloading implementation to cover this case. Bad design!
In the C++ primer, I found that const int & can bind with a int object.I don't understand that,because I think const int & should bind with a const int not a int object, the int object can change, the book explain this question for that when the const int & object bind with int; there is a temporary object between the two, for example:
int a=0;
const int &r=a;
We can use b as the temporary value, so above is equal that:
const int b=a;
const int &r=b;
But I think the book is not right, because if there is a temporary like b existing between a and r,the value of r can't be changed, but when I debug the following coding in visual studio, I found it is not right:
int a=0;
const int &r=a;
a=3;
cout<<r<<endl;
The output is that r=3; the value of r can be changed, why? I don't understand that.
don't understand that,because I think const int & should bind with a const int not a int object
You are mistaken. A reference-to-const (const reference in short) doesn't mean that only const objects can be bound. It means that the object can not be modified through the reference.
What is not allowed would be to bind a non-const reference to a const object, because such reference could be used to modify the object which would break the constness.
the value of r can be changed, why?
The object that r refers to was modified - which is OK because the object isn't const. r still refers to the same object and the object was not modified using r.
Having a const reference does not mean that the referred object can not change. It means that the object can not be changed using that reference.
If you wish to have an object that can not change, then that object itself has to be const. A const reference does not make the referred object const. The book has shown you how to create a const object:
const int b=a;
I have regarded reference as poiter mistakely,because they are similiar some time.
Indeed, references are very similar to pointers. Regarding the context of this question, they behave similarly. A demo:
int a=0;
const int *r=&a;
a=3;
cout<<*r<<endl;
const in this example only guarantee that a can not be changed where r is used. Usually this is used for functions that do not change input parameters like:
int doNotModifyFoo(const int &foo);
An object cannot be modified "through" a const reference or a pointer to const of it. But a const reference or pointer to const doesn't impose any kind of run-time lock on the underlying object and (assuming it was not declared const) the original declaration or any non-const reference or pointer to non-const can still be used to modify it.
Indeed if the object was not originally declared const then const-ness can be cast away and used to modify the underlying object.
Indeed even if the object was originally declared const this may be possible (but is implementation dependent).
const is a way of indicating that a function (or functions) shouldn't modify an object (either as an argument in our return value out or declaration).
It doesn't (in general) mean the object can't be modified through that or some other reference/pointer.
It also not possible to modify what a reference refers to. Or at least there is no valid way of doing it. In some circumstances it is possible in practice by jiggery pokery of obtaining an address of where a reference is held and modifying it like a pointer. That will usually fail in some circumstances because references are often optimized out of existence and because the compiler knows they 'cannot be modified' such violations might only be partially successful.
In C++, you can refer to non-const objects with references and/or pointers to const.
int x = 10;
const int& r = x; //OK
const int* p = &x; //OK
Of course, since x is not constant it can be changed. However, what you're basically saying by having a const reference to a non-const object is: I will not change this object via this reference/pointer. You still can change the object directly or through other references or pointers.
Think of it as a read-only handle. Yes, the object itself may be mutable, but in many cases you may be willing to acquire and/or provide only a read-only access to that otherwise mutable variable.
int a=0;
const int &r=a;
a=3;
cout<<r<<endl;
The output is that r=3; the value of r can be changed, why? I don't
understand that.
The const only applies to the reference r. It means that you can't change whatever r binded to via r. You can't do:
r = 3;
That will be an error, because r is a const int& and cannot be modified. For now you can think of references as some sort of lightweight transparent "proxy" of an object. So if the "proxy" is const, you cannot modify the object through the "proxy". However, it doesn't mean the original object cannot be modified.
Basically, const int & r promises not to mutate the value it's referencing. This is a stronger guarantee than int &. So, it's possible to refer to an int using a const int & reference. But you may not modify it. It's a subset of the operations possible on the value. However, it's not true the other way around, if you were trying to get a int & reference to an const int value, it would result in a compiler error because the value itself is immutable, and you are trying to get a mutable reference to this immutable value. The operations possible on the int & reference are a superset of what's possible on const int value.
The value of the variable a which is 0 initially is holded at memory.
If you write later: a=5, it'll set that value in memory to 5.
When you write a reference const int & r = a; you are only saying that r should access that same place in memory where 5 is being hold.
Because a is not const it can modify the value.
This is basically how it works.
There are two things:
Const and reference.
Reference is just another name for same memory unit. You can use any name to change the value held at that memory.
A const reference is denoted in C++ by a code like
int j =2;
int const &i = j; //or Alternatively
const int &i = j;
There is no restriction which makes the referred object to be constant as well.
Here, you can not use i to change value of j. However this does not make the memory location j to be constant.You can peacefully change the value of j.
j =3
//but i = 3 will raise an error saying
//assignment of read-only reference ‘i’
Is this safe?
const int& f()
{
return 1;
}
What I'm trying to do is to return a some value to const &
It is not okay.
Returning reference to a temporary is not okay because accessing it outside the function causes Undefined Behavior.
No, you're returning a reference to a temporary variable - this is not safe. The temporary variable will have been destroyed upon function return.