In the following example:
http://coliru.stacked-crooked.com/a/7a1df22bb73f6030
struct D{
int i;
auto test2(int&& j){
return [&](){ // captured by reference!
cout << i*(j);
};
}
};
int main()
{
D d{10};
{
auto fn = d.test2(10);
fn(); // 1. wrong result here
d.test2(10)(); // 2. but ok here
}
}
Why does d.test2(10)(); work?
Should it really work, or thats just my undefined behavior equals correct result?
P.S. After reading this I see only one explanation: in (2) temporary lifetime prolongs till the end of the expression, and call happens in the same expression with && crteation; while (1) actually consists from 2 expressions:
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.
Is this the case?
A temporary object lasts until the end of the line (well, full expression) where it is created, unless the lifetime is extended.
Your code does not extend the lifetimes of any temporaries. Lifetime extension through binding to references does not "commute", only the first binding extends lifetime.
So the furst case is UB as you have a dangling reference. The referred to temporary goes away st the end of the line: on the next line uou follow the reference, and chaos hapens.
In the second case, your reference does not extend the lifetime of the temporary, but the temporary lasts longer than the reference that binds to it does! They both die at the end of the line, in reverse order of construction.
So the call works.
Should it really work, or thats just my undefined behavior equals correct result?
Seems like it. In the example you linked, you have these warnings:
warning: '<anonymous>' is used uninitialized in this function [-Wuninitialized]
Uninitialized objects have indetermine values, and trying to access those values results in undefined behavior.
Related
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;
}
Is the following function safe in C++03 or C++11 or does it exhibit UB?
string const &min(string const &a, string const &b) {
return a < b ? a : b;
}
int main() {
cout << min("A", "B");
}
Is it OK to return a reference to an object passed to the function by
reference?
Is it guaranteed that the temporary string object is
not destroyed too soon?
Is there any chance that the given function
min could exhibit UB (if it does not in the given context)?
Is it possible to make an equivalent, but safe function while still avoiding
copying or moving?
Is it OK to return a reference to an object passed to the function by reference?
As long as the object isn't destroyed before you access it via that reference, yes.
Is it guaranteed that the temporary string object is not destroyed too soon?
In this case, yes. A temporary lasts until the end of the full expression which creates it, so it is not destroyed until after being streamed to cout.
Is there any chance that the given function min could exhibit UB (if it does not in the given context)?
Yes, here is an example:
auto const & r = min("A", "B"); // r is a reference to one of the temporaries
cout << r; // Whoops! Both temporaries have been destroyed
Is it possible to make an equivalent, but safe function while still avoiding copying or moving?
I don't think so; but this function is safe as long as you don't keep hold of a reference to its result.
Your temporary objects will stay "alive" till the end of the ; from the cout in main, so this way of using it is safe.
Yes, it's safe. The string temps for both "A" and "B" will survive until the end of the 'sequence point', that is the semicolon.
Is it guaranteed that the temporary string object is not destroyed too
soon
For your specific case yes, BUT for the following code no
int main() {
const string &tempString(min("A", "B"));
cout << tempString;
}
Beside that I agree with what "Mike Seymour" said.
yes it is safe to pass reference through function because in the changes always made in the arguments which you pass by value and in the above code string temps for both A and B will survive until the end of the 'sequence point' that is the semicolon but in case of pass by reference the changes made in copy of that argument not in a original copy.
void foo(const Object & o = Object()) {
return;
}
In the function above, when is ~Object supposed to be called ? when the function exit or when at the end of the block surrounding the call site ?
The default argument will be destroyed at the end of the complete expression that contains the function call.
To elaborate a bit on what David said, the standard says in section 12.2 [class.temporary]:
There are two contexts in which temporaries are destroyed at a
different point than the end of the full-expression. [...] The second
context is when a reference is bound to a temporary. The temporary to
which the reference is bound or the temporary that is the complete
object of a subobject to which the reference is bound persists for the
lifetime of the reference except:
...
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.
...
So they are neither destroyed when the function exits nor when the block containing the call ends, but at the end of the complete statement that contains the function call (simply said, at the first semicolon after the function call, in the calling context).
EDIT: So say we got:
int foo(const Object & o = Object());
some_stuff();
std::cout << (foo() + 7);
other_stuff();
This sould be roughly equivalent to the following (mind the conceptual scope block):
some_stuff();
{
Object o; // create temprorary
int i = foo(o); // and use it
int j = i + 7; // do other things
std::cout << j; // while o still alive
} // finally destroy o
other_stuff();
EDIT: As pointed out by Michael in his comment, this "statement/semicolon"-analogy I gave is rather a simplification of the term "full-expression" and there are cases where it is a bit different, like his example:
if(foo()) bar();
Which would destroy the temporary before bar is called and thus be different from the expression statement:
foo() ? bar() : 0;
But nevertheless, the "semicolon"-analogy is often a good fit, even if a full-expression is not neccessarily the same as a statement (which can consist of multiple full-expressions).
I don't think this code should compile. You can't bind a reference to a temporary unless it's const. And if it was const the temporary should be kept alive until the end of the function expression. Just the same as a local variable defined within it.
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.