5

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?

Community
  • 1
  • 1
CollioTV
  • 684
  • 3
  • 13
  • @Chris Drew... errrh I doesn't understand – CollioTV Oct 09 '14 at 16:22
  • 3
    "I know that returning a const reference of a temporary object is ok!" No it isn't. – T.C. Oct 09 '14 at 16:26
  • 2
    http://stackoverflow.com/questions/11560339/returning-temporary-object-and-binding-to-const-reference "This is a C++ feature. The code is valid and does exactly what it appears to do.", "C++ deliberately specifies that binding a temporary object to a reference to const on the stack lengthens the lifetime of the temporary to the lifetime of the reference itself" – CollioTV Oct 09 '14 at 16:28
  • I think a better question would be why do you even want to do this? All `clone()` implementations I have seen return either a `Base*` or a `std::unique_ptr` because you are transferring ownership of a new heap allocated object. – sjdowling Oct 09 '14 at 16:29
  • @CollioTV Nevermind, I didn't read your second example properly. – Chris Drew Oct 09 '14 at 16:32
  • 2
    @CollioTV "C++ deliberately specifies that binding a temporary object to a reference to const **on the stack** lengthens the lifetime of the temporary to the lifetime of the reference itself" don't you see the problem? – Slava Oct 09 '14 at 16:35
  • Maybe you want to use a `copy constructor` instead of `clone` pattern. – tillaert Oct 09 '14 at 16:36
  • 2
    @CollioTV: "I know that returning a const reference of a temporary object is ok!" You know wrong. Returning a reference to a temporary object is never OK. The SO question you linked is not even remotely similar to what you are doing in your code. – AnT stands with Russia Oct 09 '14 at 16:40
  • @Slava now i see the problem... i'm sooo dumb> – CollioTV Oct 09 '14 at 17:37
  • @AndreyT know i see why, please excuse me.... – CollioTV Oct 09 '14 at 17:39
  • "What is happening": since the name() method is virtual, calling it requires reading a 'vtable' pointer from the object, which points to a table of methods. But the pointer (initialized by the constructor B()) could have been modified, since by now the B() has been destroyed, and the memory possibly re-used for something else. valgrind detected the possibility of that. In general, ~B() will change that pointer back to point at A's vtable before ~A() runs; but in this example the compiler probably left that out (since ~A doesn't do anything ) so you got B::name. – greggo Oct 28 '14 at 14:29

1 Answers1

11

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.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • @T.C. So, what if I have a method that returns a const reference to a subclass (or member var) of *this? The caller must be aware that the reference doesn't outlive the object on which the method was called; and if that object is a temporary, the language won't extend its lifetime by these rules, since the reference isn't being taken in the calling code, but in the method. Correct? – greggo Oct 28 '14 at 14:32