Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lifetime of rvalue bound to static const reference

Consider this:

std::string foo();

void bar() {
         const std::string& r1 = foo();
  static const std::string& r2 = foo();
}

I know that the lifetime of the string resulting from the first call to foo() will be extended to the lifetime of r1.

What about the temporary bound to r2, though? Will it live until the end of the scope or will it still be there when bar() is re-entered?

Note: I am not interested whether a particular compiler does so. (I am interested in the one we use, and I can test easily with that.) I want to know what the standard has to say on this.

like image 656
sbi Avatar asked Jul 14 '15 11:07

sbi


1 Answers

The temporary is extended to the lifetime of the reference.

[C++14: 12.2/5]: 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. [ Example:

    struct S { int mi; const std::pair<int,int>& mp; };
    S a { 1, {2,3} };
    S* p = new S{ 1, {2,3} }; // Creates dangling reference
    

—end example ] [ Note: This may introduce a dangling reference, and implementations are encouraged to issue a warning in such a case. —end note ]

(In particular, note that none of the bullet points match this scenario.)

So, in this case, it's essentially until the program ends.

We can, of course, test this pretty trivially:

#include <iostream>

struct Tracked
{
    Tracked() { std::cout << "ctor\n"; };
    Tracked(const Tracked&) { std::cout << "copy\n"; };
    ~Tracked() { std::cout << "dtor\n"; };
};

void foo()
{
    static const Tracked& ref = Tracked();
}

int main()
{
    std::cout << "main()\n";
    foo();
    std::cout << "bye\n";
}

Result:

main()
ctor
bye
dtor

(live demo)

like image 132
Lightness Races in Orbit Avatar answered Oct 14 '22 15:10

Lightness Races in Orbit