Only for curiosity and educating and clarification reasons I would like to ask that the way I use references and values are good practices or not.
Theoretically:
class ComplexGraphicalShape {
...
public:
void setRasterImageURL(const QString &rasterImageURL);
const QString &rasterImageURL() const;
...
private:
const QString *_rasterImageURL;
};
...
void ShadowGram::setRasterImageURL(const QString &rasterImageURL) {
safeDelete(_rasterImageURL); // handle deletion
_rasterImageURL = new QString(rasterImageURL);
}
const QString &ShadowGram::rasterImageURL() const{
// Question 2: Why is it a problem if I return
// return "www.url.com/shape_url.jpg"
return *_rasterImageURL; // that is the right way
}
...
complexGraphicalShape().setRasterImageURL(kURLImagesToShare + imageName);
complexGraphicalShape().setRasterImageURL("www.url.com/url.jpg"); // Question 1.
My first question is that how long can I use the temporary object reference which is created inside setRasterImageURL functioncall? Where exist that variable?(in the stack If I am not mistaken, but what if I call another function with that temporary reference.
My second question is that why I got a warning in Question 2 section if I would like to use this return "www.url.com/shape_url.jpg"? That thing is kind of similar. How long can I use that temporary object?
Thanks for your time for the answer and explanations
The temporary exists until setRasterImageURL returns, so you can safely pass a reference to it along, but you need to be careful not to save the reference for later. The temporary is stored wherever the compiler wants to. The reference is most likely passed either in a register or on the stack.
It is a problem because you're returning a reference to a temporary QString object, and that object is destroyed when the function returns. You're not allowed to use the reference at all.
Passing a reference "inwards" to a function is (usually) safe as long as you don't store it, while passing a reference "outwards" from a function requires you to make sure that the referenced object still exists when the function returns.
Q1: The temporary string exists as long as the temporary reference that is "bound" to it. That is - as long as you are "inside" setRasterImageURL() function. This - of course - includes all functions called "within" this function. Note that storing another reference to this temporary string does NOT prolong the lifetime of the temporary object.
complexGraphicalShape().setRasterImageURL("www.url.com/url.jpg");
// the temporary object is "destroyed" when it goes out of scope, and it's scope is just the called function
Q2: The problem with returning is that you use "C string" (array of characters) to create a temporary QString object (on stack, still inside the function) and return reference to that temporary. As this temporary object is destroyed right after this function returns, your reference is never valid and refers to a dead object. On the other hand - returning a reference to a member variable works, because this object is not destroyed, so the reference is valid as long as your main object lives.
const QString &ShadowGram::rasterImageURL() const{
return "www.url.com/shape_url.jpg"
// the temporary object is destroyed here, before the function returns, reference is invalid
}
My first question is that how long can I use the temporary object reference which is created inside setRasterImageURL functioncall?
It's not created inside the function call, it's created on the caller's stack before the function is called, and is destroyed after the function returns.
Where exist that variable?(in the stack If I am not mistaken, but what if I call another function with that temporary reference.
Yes, on the stack. It is destroyed at the ; after the function call returns (at the end of the "full expression").
That thing is kind of similar. How long can I use that temporary object?
Until the end of the full expression that creates the temporary, which is the return statement, so it goes out of scope immediately before the function has even finished returning. That's why you get a warning - the returned reference is bound to an object which no longer exists, and is never safe to use.
Both these cases are covered by 12.2 [class.temporary] paragraph 5 in the standard:
— A temporary object bound to a reference parameter in a function call (5.2.2) persists until the completion of the full-expression containing the call.
— The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.
Related
Pass by reference:
I have learned that when a variables is passed as a reference to a function then instead of copy, the actual data is passed to the function but i think that if it is really the case then we shouldn't be able to access that data again once the program execution returns to main() after the stack frame of that function gets destroyed and leave that reference variable with zero or null value in main() but it is not the case and we can still access it in the main() so i think that in pass by reference, the memory address of that variable is passed to that function reference variable parameter and then we use that memory in that function with another name(reference variable) and when that function gets destroyed then the reference variables get destroyed rather than the actual data.
is my thinking towards this concept is right or am i doing some mistake in understanding this concept ?
Return By Reference
When a variable which is passed as a reference to another function returns back as a reference to main() then is the memory address passed back to main() or what actually is returned ?
I have learned that when a variables is passed as a reference to a function then instead of copy, the actual data is passed to the function
This is wrong. Passing the actual data would mean the value is passed (either by copy or by move). When passing by reference, a reference to the actual data is passed to the function.
so i think that in pass by reference, the memory address of that variable is passed to that function reference variable parameter and then we use that memory in that function with another name(reference variable)
This is right.
When a variable which is passed as a reference to another function returns back as a reference to main() then is the memory address passed back to main() or what actually is returned ?
A reference can be thought of as a memory address, so returning a reference is similar to returning a pointer (memory address).
When returning a reference from a function, you need to be careful that you don't return a reference to a variable that's local to the function, because that variable no longer exists after the function returns, and you are left with a dangling reference that may crash your program when you try to use it.
passed as a reference to a function then instead of copy, the actual data is passed to the function
It is unclear what you mean by "actual" data. A copy is actual data as much as the origianl object is.
References are a form of indirection. The reference variable indirectly refers to the object to which it was bound. An object variable is distinct from other objects, and its value may be copied from another.
if it is really the case then we shouldn't be able to access that data again once the program execution returns to main()
Binding a reference to an object does not make the object or its data disappear. Example:
void foo(int& ref);
int main()
{
int obj;
foo(obj);
// obj still exists here
}
If you bind a reference to an object defined in main, then the object still exists in main regardless of where that reference was bound.
i doing some mistake in understanding this concept ?
Yes. You did not understand yet what a reference is, or at least were not able to describe them correctly.
Your concept of pass by reference is wrong.
Passing a variable to a function by reference means that something else (let's call it a handle) is passed that acts an alias of the original variable. Every operation that can be performed on the handle within the function (e.g. assigning it a value, retrieving its value, calculating its address, calling a member function if it is an object) are referred to the original variable that was passed by the caller. How those affects are achieved depends on the implementation (e.g. the compiler).
The called function, by performing operations on the handle, does not cause the original variable to cease to exist. (Except in some very specific circumstances, which I won't go into).
For example;
#include <iostream>
void foo(int &x)
{
x = 42; // x is the handle I refer to above
}
int main()
{
int y = 16;
std::cout << y << '\n';
foo(y);
std::cout << y << '\n';
}
will print the values 16 and 42, in that order. The assignment x = 42 in foo() has the effect of changing the value of y in main(). The lifetime of y is unaffected, so y continues to exist until the end of main().
That thing I have referred to as a "handle" is more commonly known as a reference.
Similarly, your concept of returning a reference is wrong. Returning a reference gives a handle to the caller, and the caller can then use the returned handle to access (and perform operations on) whatever variable is returned by the function.
Note that, in the above, I have said nothing about passing the address of a variable around. Because the description above focuses on the observable effect of using references, not on how that observable effect is achieved (e.g. by the compiler).
Behind the scenes, your compiler MIGHT implement all of the magic of references by passing the address of the affected variables around (in fact, most modern compilers do). That is one possible implementation approach. But there are, technically, other ways of achieving that effect - the C++ standard does not require the address of variables to be passed around to achieve the behaviours associated with passing them around by reference.
I see once return a local object,the compiler will take the return value optimization.(RVO,NRVO).
The part of the Standard blessing the RVO goes on to say that if the
conditions for the RVO are met, but compilers choose not to perform
copy elision, the object being returned must be treated as an rvalue.
So we just write code like this:
Widget makeWidget()
{
Widget w;
…
return w;//never use std::move(w);
}
I never see somebody write code like this:
Widget&& makeWidget()
{
Widget w;
…
return std::move(w);
}
I know that returns an lvalue reference of local object is always wrong.
So, returns an rvalue reference of local object is also wrong?
Returning a reference to a local automatic variable is always wrong. The variable will be destroyed when the function returns, so any use of the reference will give undefined behaviour.
It makes no difference whether it's an rvalue or lvalue reference.
When the function return ,local object has been released.
if write code like this:
Widget&& makeWidget()
{
Widget w;
…
return std::move(w);
}
So consider the following three sections of code:
First:
Widget&& w= makeWidget();//w is a dangling reference,variable will be destroyed when the function returns
Second:
void foo(Widget&& w){...}//w is a dangling reference too
foo(makeWidget());
Third:
void foo(Widget w){...}//OK,will copy it
foo(makeWidget());
So answer is wrong.
And Note that:
Rvalue references can be used to extend the lifetime of a modifiable temporary (note, lvalue references to const can extend lifetimes too, but they are not modifiable)
Whenever a reference is bound to a temporary or to a base subobject of
a temporary, the lifetime of the temporary is extended to match the
lifetime of the reference, with the following exceptions:
a temporary bound to a return value of a function in a return statement is not extended: it is destroyed immediately at the end of
the return expression. Such function always returns a dangling reference.
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.
a temporary bound to a reference in the initializer used in a new-expression exists until the end of the full expression containing
that new-expression, not as long as the initialized object. If the initialized object outlives the full expression, its reference member
becomes a dangling reference.
Widget&& makeWidget(){
return Widget(123);//error
}
Yes, it is wrong. No reference lifetime extension occurs, so the reference refers to a destroyed value, and any use of it (almost)1 is undefined behaviour. You should not return dangling references or pointers.
1: decltype isn't really use, but it also isn't UB. So there is that. Storing a reference to it also isn't UB. Also not really use.
Unfortunately Widget w; is on a stack and while you pass the reference down to the other function the w will be destroyed... Passing the object by value will save the object from being destroyed.
Section 12.2.5 of the standard says:
A temporary bound to a reference parameter in a function call (5.2.2)
persists until the completion of the full expression containing the
call. A temporary bound to the returned value in a function return
statement (6.6.3) persists until the function exits. In all these
cases, the temporaries created during the evaluation of the expression
initializing the reference, except the temporary to which the
reference is bound, are destroyed at the end of the full-expression in
which they are created and in the reverse order of the completion of
their construction.
I'm trying to understand the following code:
#include <iostream>
const int& foo(const int& fooRef)
{
return fooRef;
} // #0
int main (void)
{
const int& numberRef = foo(5); // #1
std::cout << numberRef; // #2
return 0;
}
On line #1 a temporary object is created and bound to fooRef. fooRef is destroyed on line #0. I thought the temporary should be destroyed here since lifetime-extension is not transitive.
Questions:
What does until the function exits mean? Does it mean untill it finished executing?
Why do I get a 5 output. Does a temporary object still exist on line #2?
How can I interpret the standard quote to figure out how this example works?
Step-by-step atomic walk-through with references to the standard would be greatly appreciated. Thank you!
P. S. An accepted answer here also told the the code is broken and I do not get, why I get such output of program.
What does until the function exits mean? Does it mean untill it finished executing?
Yes.
Why do I get a 5 output. Does a temporary object still exist on line #2?
Dereferencing a reference which is not bound to a living object is undefined behavior, so you may get 5 as well as 42 as well as anything else (including a crash). You simply cannot have any expectation on a program that has undefined behavior.
How can I interpret the standard quote to figure out how this example works?
Pretty much like you did already.The temporary gets bound to the function parameter fooRef, which gets destroyed when returning from the function. Since that temporary is bound to the returned value, that object ceases to exist when the function returns. Later on, you are dereferencing a dangling reference, which gives you UB.
It means until the closing brace, i.e. }.
You invoked UB, you have a dangling reference.
Try the following modification of your code and see what it prints. It probably will print 6 because that is what was last on the stack. Or try passing a std::string instead, you might get a crash.
int main (void)
{
const int& numberRef = foo(5);
foo(6);
std::cout << numberRef;
return 0;
}
void fn(string &s)
{
//....
}
//use the function
fn("helloworld");
Firstly, it's wrong to initiate a non-const string with a const char string.
After I add const in the parameter, it compiles.
But is it right to reference a temporary object string("helloworld") on stack?
Is it sure that string("helloworld") gets called?
--
edits.
If a temporary string is created, how the compiler judges that the object string("helloworld") is const from the constructor of std::string(const char*)?
But is it right to reference a temporary object string("helloworld") on stack?
Yes, as long as the reference is const, the lifetime of the temporary will be extended.
Is it sure that string("helloworld") gets called?
Yes, a temporary is created using the conversion constructor std::string(const char*). Note however that the compiler can optimize this step out.
But is it right to reference a temporary object string("helloworld")
on stack?
In this case, probably, but you do have to pay attention to the lifetime of the object. The temporary will cease to exist at the end of the full expression; if fn saves a pointer or a reference to it, you're in trouble. This is typically not a problem with a free function, like your fn (but it can be); it could be a problem if the temporary were an argument to a constructor in a new expression (but the author of the class should document any lifetime requirements which go beyond the constructor invocation).
But is it right to reference a temporary object string("helloworld") on stack?
Yes, why not?
Is it sure that string("helloworld") gets called?
Yes, as long string provides an implicit constructor using a const char* argument this is garuanteed (std::string does so).
What happens to the reference in function parameter, if it gets destroyed when the function returns, then how const int *i is still a valid pointer?
const int* func(const int &x = 5)
{
return &x;
}
int main()
{
const int *i = func();
}
§12.2/5:
"A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full expression containing the call."
That means as i is being initialized, it's getting the address of a temporary object that does exist at that point. As soon as i is initialized, however, the temporary object will be destroyed, and i will become just another dangling pointer.
As such, yes, the function is valid -- but with the surrounding code as you've written it, any code you added afterward that attempted to dereference i would give undefined behavior.
Just because a pointer has a value doesn't mean it's a valid pointer.
In this case it holds an address which used to be that of x, and chances are that address still has the value 5, but it's not valid pointer and you can't count on that value being there.
int i points to a patch of memory that is unsafe to access, it is not a valid pointer.
the variable "i" is still a pointer, but even reading the value it points to will give you undefined behavior. That's why you should never write a function like func.
I think that x is created as an un-named temporary on the stack in setting up the call to func(). This temporary will exist until at least the end of the statement in the caller. So the int* i is perfectly valid. It only ceases to be valid at the end of the statement - which means that you cannot use it.
There is something in the standard about un-named temporaries being retained until the last reference to them goes out of scope, but I don't think it covers this explicit and hidden indirection.
[ Happy to have someone tell me otherwise.]
5 is program data. It is in the data segment, not the stack or heap.
So a pointer or reference to it will remain valid for the duration of the program.
Default arguments are evaluated every time the function is called, so the call func() is actually func(5) which is binding a temporary to a reference-to-const. The lifetime of that temporary is then extended till the end of the function and the object is destroyed. Any pointer to this object after that is invalid and dereferencing it is undefined behaviour.