return const reference of subclass - c++

What I know
I know that returning a const reference of a temporary object is ok! (like this example:)
class A {
public:
virtual const A& clone () { return (A()); }
virtual std::string name() const { return ("A"); }
};
Returning temporary object and binding to const reference
But!
If I would want to do that, It is still correct:
class B : public A {
public:
virtual const A& clone () { return (B()); }
virtual std::string name() const { return ("B"); }
};
I would think yes, but in execution time, the returned object is still considered as a A object (like in this example:)
main.cpp
#include <iostream>
#include <string>
int main() {
B bb;
A* aa = &bb;
std::cout << aa->clone().name() << std::endl;
}
output
valgrind ./a.out
==14106== Use of uninitialised value of size 8
==14106== at 0x401BF9: main (main.cpp:8)
==14106== Uninitialised value was created by a stack allocation
==14106== at 0x401BF2: main (main.cpp:8)
B
It's a B.. yay.. but this warning is quite horrifing....
Edit
Thanks to you i know see my error... but i would want to know some other things about it...
When this is executed, what exactly in the stack is happening?

Binding a reference to a temporary extends the lifetime of the temporary...except when it doesn't. §12.2 [class.temporary]/p5, emphasis added:
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 member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits.
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.
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.
A temporary bound to a reference in a new-initializer (5.3.4) persists until the completion of the full-expression containing the
new-initializer.
The case in the question you linked (std::string foo(); const std::string & s = foo();) is OK; the lifetime of the temporary returned by foo() is extended until s's lifetime ends. In your code, the temporary is bound to the returned value, and per the third bullet point above, its lifetime is not extended, and your function returns a dangling reference.
Usually speaking, clone() functions should return a pointer to a heap-allocated copy.

Related

Returning const reference

I'm somewhat confused about the declaration of functions returning const references to temporaries.
In the following code
#include <string>
#include <iostream>
using namespace std;
const string& foo() {
return string("foo");
}
string bar() {
return string("bar");
}
int main() {
const string& f = foo();
const string& b = bar();
cout << b;
}
What is the difference between methods foo and bar ?
Why does foo give me warning: returning reference to local temporary object [-Wreturn-stack-address]. Isn't a copy of the temporary created on const string& f = foo(); ?
string("foo") creates an object of type std::string containing the value "foo" locally in the function. This object will be destroyed at the end of the function. So returning the reference to that object will be invalid once the code leaves that function [1]. So in main, you will never have a valid reference to that string. The same would be true if you created a local variable inside foo.
The WHOLE point of returning a reference is that you don't make a copy, and initializing a reference (string &f = foo() is an initialization) will not create a copy of the original object - just another reference to the same object [which is already invalid by the time the code is back in main]. For many things, references can be seen as "a different name for the same thing".
The lifetime of the referred object (in other words, the actual object the "alias name" refers to) should ALWAYS have a lifetime longer than the reference variable (f in this case).
In the case of bar, the code will make a copy as part of the return string("bar");, since you are returning that object without taking its reference - in other words, by copying the object, so that works.
[1] pedantically, while still inside the function, but after the end of the code you have written within the function, in the bit of code the compiler introduced to deal with the destruction of objects created in the function.
Isn't a copy of the temporary created on const string& f = foo();
Where did you hear that?
Adding const to a reference often allows the lifetime of a temporary with which it's been initialised to be extended to the lifetime of the reference itself. There's never a copy.
Even that's not the case here, though. The object you're binding to the reference goes out of scope at the end of the function and that takes precedence over everything else.
You're returning a dangling reference; period.
Why does foo give me warning: returning reference to local temporary
object [-Wreturn-stack-address].
You are creating a temporary string object inside foo(), and you are returning a reference to that object which will immediately go out of scope (dangling reference).
const string& foo() {
return string("foo"); // returns constant reference to temporary object
} // object goes out of scope
bar() is quite different:
string bar() {
return string("bar"); // returns a copy of temporary string
}
...
const string& b = bar(); // reference an rvalue string
What is the difference between methods foo and bar ?
foo() returns a constant (dangling) reference while bar() returns a copy of a temporary string object.
In both of the cases, a string object is initialized and allocated on the stack.
After returning from the function, the memory segment which contains it becomes irrelevant, and its content may be overridden.
The difference between the functions:
bar function return a copy of the string instance which is created inside it.
foo function returns a reference to the string instance which is created inside it.
In other words, it returns an implicit pointer to its return value, which resides in a temporary memory segment - and that's the reason for your warning.

Why does std::reference_wrapper<const T> not accept a temporary?

Normally, rvalues can bind to const references (const SomeType&). It's built into the language. However, std::reference_wrapper<const T> does not accept an rvalue as its constructor argument since the corresponding overload is deliberately deleted. What is the reason for this inconsistency? std::reference_wrapper is "advertised" as the alternative to a reference variable for cases when we must pass by value but would like to preserve reference semantics.
In other words, if the rvalue to const & binding is considered safe, since it's built into the language, why did the designers of C++11 not allow rvalues to be wrapped in std::reference_wrapper<const T>?
When would this come handy, you may ask. For example:
class MyType{};
class Foo {
public:
Foo(const MyType& param){}
};
class MultiFoo {
public:
MultiFoo(std::initializer_list<std::reference_wrapper<const MyType>> params){}
};
int main()
{
Foo foo{MyType{}}; //ok
MultiFoo multiFoo{MyType{}, MyType{}}; //error
}
INTRODUCTION
Normally T const& and T&& can extend the lifetime of a temporary directly bound to it, but this is not applicable if the reference is "hiding" behind a constructor.
Since std::reference_wrapper is copyable (by intention), the handle to the referenced object can outlive the temporary if the std::reference_wrapper is used in such a way that the handle escapes the scope where the temporary is created.
This will lead to a lifetime mismatch between the handle and the referred to object (ie. the temporary).
LET'S PLAY "MAKE BELIEVE"
Imagine having the below, illegal, snippet; where we pretend that std::reference_wrapper has a constructor that would accept a temporary.
Let's also pretend that the temporary passed to the constructor will have its lifetime extended (even though this isn't the case, in real life it will be "dead" right after (1)).
typedef std::reference_wrapper<std::string const> string_ref;
string_ref get_ref () {
string_ref temp_ref { std::string { "temporary" } }; // (1)
return temp_ref;
}
int main () {
string_ref val = get_ref ();
val.get (); // the temporary has been deconstructed, this is dangling reference!
}
Since a temporary is created with automatic storage duration, it will be allocated on the storage bound to the scope inside get_ref.
When get_ref later returns, our temporary will be destroyed. This means that our val in main would refer to an invalid object, since the original object is no longer in existance.
The above is the reason why std::reference_wrapper's constructor doesn't have an overload that accepts temporaries.
ANOTHER EXAMPLE
struct A {
A (std::string const& r)
: ref (r)
{ }
std::string const& ref;
};
A foo { std::string { "temporary " } };
foo.ref = ...; // DANGLING REFERENCE!
The lifetime of std::string { "temporary" } will not be extended, as can be read in the standard.
12.2p5 Temporary objects [class.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 member in a constructor's ctor-initializer (12.6.2) persists until the constructor exits.
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.
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.
A temporary bound to a reference in a new-initializer (5.3.4) persists until the completion of the full-expression containing the new-initializer.
Note: it's important to note that a constructor is nothing more than a "fancy" function, called upon object construction.
Binding a temporary directly to a reference prolongs its lifetime.
struct Foo {};
Foo f() { return {}; }
void g() {
f(); // temporary destroyed at end of full-expression
const Foo& r = f(); // temporary destroyed at end of scope
// r can still be used here ...
// ...
// all the way down to here
}
However, it must bind directly to the temporary. Consider the following example:
struct Bar {
Bar(const Foo& f): r(f) {}
const Foo& r;
};
void h() {
Bar b(f());
// binding occurs through parameter "f" rather than directly to temporary "f()"
// b.r is now a dangling reference! lifetime not extended
}
Which would make it quite useless to wrap a temporary, even if you could.
Note: an actual reference wrapper object uses a pointer, so that it can be reassigned:
struct Baz {
Baz(const Foo& f): p(std::addressof(f)) {}
Baz& operator=(const Foo& f) { p = std::addressof(f); return *this; }
const Foo* p;
};
The same still applies: the temporary passed into the constructor or assignment operator will be destroyed at the end of the full-expression containing the call.
You should not copy a const reference as it does not necessarily keep the referenced object alive. The following code shows the problem:
#include <iostream>
struct X { int x; };
struct Foo {
const X& a;
Foo(const X& na) : a(na) {} // here na is still OK
};
int main()
{
Foo foo{X{3}}; // the temporary exists only for this expression
// now the temporary is no longer alive and foo.a is a dangling reference
std::cout << foo.a.x << std::endl; // undefined behavior
}
The const reference keeps the temporary X{3} alive for the constructor of Foo, but not for the object itself. You get a dangling reference.
To protected you from this problem the usage of temporary objects with std::reference_wrapper and std::ref has been disabled.
Since a const T&& variable can nor be moved, neither modified, there's no reason for using it (there's no adventages or differences over a const T&). Even more, a posterior use of that reference can be dangerous if the corresponding temporary is no longer alive (actually, it's dangerous, because it invokes undefined behaviour in such a case).
The deletion of its rvalue-reference constructor is not a bad idea after all.

Const reference as class member

Even if the subject was discussed many times around here, I can't find a conclusive explanation regarding my particular case. Will const extend the lifetime of the RefTest temporary? Is the below example legal?
#include <iostream>
class RefTest
{
public:
RefTest(const std::string &input) : str(input) {}
~RefTest () {std::cout << "RefTest" << std::endl;}
private:
std::string str;
};
class Child
{
public:
Child (const RefTest &ref) : ref_m(ref) {}
~Child () {std::cout << "Test" << std::endl;}
private:
const RefTest &ref_m;
};
class Test
{
public:
Test () : child(RefTest("child")) {}//Will the temporary get destroyed here?
~Test () {std::cout << "Test" << std::endl;}
private:
const Child child;
};
int main ()
{
Test test;
}
The reference does not extend the lifetime. The code is legal, but only because you never access ref_m after the constructor finishes.
The temporary is bound to the constructor parameter, ref. Binding another reference to it later, ref_m, doesn't extend the lifetime. If it did, you'd have an object on the stack which has to persist as long as the reference member it's bound to, which could be allocated on the heap, so the compiler would be unable to unwind the stack when the constructor returns.
It would be nice to get a warning, but compilers aren't perfect and some things are difficult to warn about. The temporary is created in a different context from where it's bound to a reference, so the compiler can only tell there's a problem with inlinging turned on, or some clever static analysis.
The C++ standard states:
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 to a subobject of which the temporary is bound
persists for the lifetime of the reference except as specified below.
A temporary bound to a reference member in a constructor’s
ctor-initializer (12.6.2) persists until the constructor exits. 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.
NOTE: And by the way, this is duplicate (1, 2), you should search better, next time... :)

What is the lifetime of the class data member which const reference to a rvalue?

Generally this discussion is up to the local function variable only:
void foo (const int &i)
{
// use i till foo() ends
}
foo(3);
But, does this rule applies to the class member also ?
struct A {
const int &a;
A () : a(3) {} // version 1
A (const int &i) : a(i) {} // version 2
};
Now A used as,
{
return ()? new A : new A(3) : new A(some_local_variable);
}
Will the contents of a remain same through out the life time of the all 3 newly allocated A ?
The C++03 standard (Section "12.2/5 Temporary objects") answers your question aptly:
The temporary to which the reference is bound or the temporary that is the complete object to a subobject of which the temporary is bound persists for the lifetime of the reference except as specified below. A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits. 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.
If you allocate an object using new, it will remain in memory forever - until you delete it. It's not a temporary object.
a is a member of A, and as such part of the allocation.
EDIT: Thanks for the comments. I would say - no, this is not correct. Consider this:
struct A {
const int &a;
A () : a(3) {} // version 1
A (const int &i) : a(i) {} // version 2
};
void foo() {
A *pA;
{
int x;
pA = new A(x);
}
// Now pA->a is pointing to the address where `x` used to be,
// but the compiler may very well put something else in this place now
// because x is out of scope.
}
The answer is more obvious if the lifetime of the A object spans across several functions.
Side note: I find the word "contents" a bit ambiguous here. Equate the reference with a pointer, so your a is basically pointing to an integer. const or not, if the integer does no longer exist (because it was on the stack and has been removed), your a - while still pointing to the same address in memory - is referencing something else now. The GotW article appears to be talking about the compiler prolonging the lifetime of the object being pointed to by the reference. The reference itself, again, is just a pointer.

How is its lifetime of a return value extended to the scope of the calling function when it is bound to a const reference in the calling function?

"If you return a value (not a reference) from the function, then bind it to a const reference in the calling function, its lifetime would be extended to the scope of the calling function."
So: CASE A
const BoundingBox Player::GetBoundingBox(void)
{
return BoundingBox( &GetBoundingSphere() );
}
Returns a value of type const BoundingBox from function GetBoundingBox()
variant I: (Bind it to a const reference)
const BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox();
variant II: (Bind it to a const copy)
const BoundingBox l_Bbox = l_pPlayer->GetBoundingBox();
Both work fine and I don't see the l_Bbox object going out of scope. (Though, I understand in variant one, the copy constructor is not called and thus is slightly better than variant II).
Also, for comparison, I made the following changes.
CASE B
BoundingBox Player::GetBoundingBox(void)
{
return BoundingBox( &GetBoundingSphere() );
}
with Variants:
I
BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox();
and II:
BoundingBox l_Bbox = l_pPlayer->GetBoundingBox();
The object l_Bbox still does not go out scope. How does "bind it to a const reference in the calling function, its lifetime would be extended to the scope of the calling function", really extend the lifetime of the object to the scope of the calling function ?
Am I missing something trivial here?
Normally a temporary object (such as one returned by a function call) has a lifetime that extends to the end of the "enclosing expression". However, a temporary bound to a reference generally has it's lifetime 'promoted' to the lifetime of the reference (which may or may not be the lifetime of the calling function), but there are a couple exceptions. This is covered by the standard in 12.2/5 "Temporary objects":
The temporary to which the reference is bound or the temporary that is the complete object to a subobject of which the temporary is bound persists for the lifetime of the reference except as specified below. A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits. 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.
See the following for more information:
C++ constant reference lifetime (container adaptor)
GotW #88: A Candidate For the "Most Important const"
An example that might help visualize what's going on:
#include <iostream>
#include <string>
class foo {
public:
foo( std::string const& n) : name(n) {
std::cout << "foo ctor - " << name + " created\n";
};
foo( foo const& other) : name( other.name + " copy") {
std::cout << "foo copy ctor - " << name + " created\n";
};
~foo() {
std::cout << name + " destroyed\n";
};
std::string getname() const { return name; };
foo getcopy() const { return foo( *this); };
private:
std::string name;
};
std::ostream& operator<<( std::ostream& strm, foo const& f) {
strm << f.getname();
return strm;
}
int main()
{
foo x( "x");
std::cout << x.getcopy() << std::endl;
std::cout << "note that the temp has already been destroyed\n\n\n";
foo const& ref( x.getcopy());
std::cout << ref << std::endl;
std::cout << "the temp won't be deleted until after this...\n\n";
std::cout << "note that the temp has *not* been destroyed yet...\n\n";
}
Which displays:
foo ctor - x created
foo copy ctor - x copy created
x copy
x copy destroyed
note that the temp has already been destroyed
foo copy ctor - x copy created
x copy
the temp won't be deleted until after this...
note that the temp has *not* been destroyed yet...
x copy destroyed
x destroyed
Firstly, the lifetime of temporary object gets extended to the lifetime of const reference that's bound to it, not "to the scope of the calling function" (although maybe that what you meant by that strange wording "the scope of the calling function"). This is what your CASE A illustrates, where you attach a const reference to a temporary. The temporary continues to live as long as the reference lives. When the reference ends its lifetime, the temporary object gets destroyed as well.
Secondly, your CASE B is simply ill-formed, non-compilable. Namely, the
BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox();
is illegal. It is illegal in C++ to attach a non-const reference to a temporary. If your compiler allows it, it must be a quirk/extension of your compiler, which has little to do with C++ language.
The point is that when returning by value, the value is copied into the variable you are assigning the result of the function. (just like you said - the copy constructor is called). No lifetime extension, you just create a brand-new object.
When returning by reference, under the hood you just pass the pointer to the variable defined in the function. So, a new object is not created, you just have reference to it outside the function. With that case the lifetime of an function-inside variable is extended.
Usually, if you return an object by value from a function, the said object will be destroyed when the assignment expression is finished:
myclass X = getX(); // after copy constructor, the returned value is destroyed
// (but you still hold a copy in X)
In the case you describe, the returned value will be destroyed later on, allowing you to use it:
const myclass& X = getX();
cout << X.a << endl; // still can access the returned value, it's not destroyed