Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

return const reference of subclass

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?

like image 299
CollioTV Avatar asked Oct 09 '14 16:10

CollioTV


1 Answers

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.

like image 97
T.C. Avatar answered Oct 17 '22 13:10

T.C.