I'd like to pass a reference into a function. This code does not work, as I'd expect:
struct A {
};
void foo(A& a) {
// do something with a
}
int main(int, char**) {
foo(A());
}
I get the compile error
invalid initialization of non-const reference of type
A&
from an rvalue of typeA
But when I just add the method A& ref()
to A
like below and call it before passing it along, it seems I can use a
. When debugging, the A
object is destroyed after foo()
is called:
struct A {
A& ref() {
return *this;
}
};
void foo(A& a) {
// do something with a
}
int main(int, char**) {
foo(A().ref());
}
Is this valid code according to the standard? Does calling ref()
magically extend the lifetime of the object until foo()
returns?
The reference disappears, the object continues to live. P.S. You are using the term scope incorrectly. Scope is the visibility region for an identifier. Scope by itself has nothing to do with object lifetime.
The lifetime of a variable is the time during which the variable stays in memory and is therefore accessible during program execution. The variables that are local to a method are created the moment the method is activated (exactly as formal parameters) and are destroyed when the activation of the method terminates.
C/C++ use lexical scoping. The lifetime of a variable or object is the time period in which the variable/object has valid memory. Lifetime is also called "allocation method" or "storage duration."
The lifetime of an object begins when its initialization is complete, and ends when its storage is released. Dynamic storage duration starts when the storage created by (new Type) is initialized, and ends when the object goes out of scope or is deleted by “delete pointer”.
Your code is perfectly valid.
In this line
foo(A().ref());
The instance of a temporary A
lives until the end of the statement (;
).
That's why it's safe to pass A&
returned from ref()
to foo
(as long as foo
doesn't store it).
ref()
by itself does not extend any lifetime, but it helps by returning an lvalue reference.
What happens in the case of foo(A());
? Here the temporary is passed as an rvalue. And in C++ an rvalue does not bind to non-const lvalue references (even in C++11, an rvalue reference does not bind to non-const lvalue references).
From this Visual C++ blog article about rvalue references:
... C++ doesn't want you to accidentally modify temporaries, but directly calling a non-const member function on a modifiable rvalue is explicit, so it's allowed ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With