11

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;
}
Mihai Todor
  • 8,014
  • 9
  • 49
  • 86
  • 5
    That last line isn't creating an object at all. It's declaring a function. See http://en.wikipedia.org/wiki/Most_vexing_parse. – Oliver Charlesworth Mar 20 '13 at 01:40
  • @OliCharlesworth Oh, shoot. I was afraid the example is stupid :( Please see my updated one, which should be a bit closer to my real-life situation. This time, I don't think there should be any vexing parse issues. – Mihai Todor Mar 20 '13 at 01:52
  • @NayanaAdassuriya which `test2`? I had rewrite my initial example, because I didn't put enough thought in it. – Mihai Todor Mar 20 '13 at 01:59
  • possible duplicate of [Does a const reference prolong the life of a temporary?](http://stackoverflow.com/questions/2784262/does-a-const-reference-prolong-the-life-of-a-temporary) – Carl Mar 20 '13 at 02:15
  • @carleeto Yes, Haroogan already linked it. Thanks. – Mihai Todor Mar 20 '13 at 02:22

2 Answers2

12

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.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • Oh, bloody hell. It didn't occur to me that it will bind to the function parameter, rather than the internal member. Thank you for pointing that out. – Mihai Todor Mar 20 '13 at 02:05
  • Even if you create a temporary in the child constructor e.g. `ref_m(RefTest(""))` then it won't extend the lifetime past the end of the constructor, for the same reason that the temporary is in the constructor's stack frame and has to be destroyed when that function returns. The standard explicitly says: "A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits." 12.2 [class.temporary] – Jonathan Wakely Mar 20 '13 at 02:08
  • Indeed. Then most of the answers I've seen here related to my question are misleading. I was under the impression that if I assign a temporary to a **const** reference, then the object will be destroyed only after the reference goes out of scope, and not the temporary itself. – Mihai Todor Mar 20 '13 at 02:11
9

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... :)

Community
  • 1
  • 1
Alexander Shukaev
  • 16,674
  • 8
  • 70
  • 85
  • Yes, now it's clear. Thank you for the quote from the standard. – Mihai Todor Mar 20 '13 at 02:07
  • Thanks for the references in the edit. There are too many questions around here on this subject and now I can understand why... Most of them gave me the impression that assigning a temporary to a const reference will prolong its life until the reference goes out of scope. – Mihai Todor Mar 20 '13 at 02:14