Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ lifetime of temporaries - is this safe?

Tags:

c++

c++11

If I understand the rules for the lifetime of temporaries correctly, this code should be safe since the lifetime of the temporary stringstream in make_string() lasts until the end of the complete expression. I'm not 100% confident there's not a subtle problem here though, can anyone confirm if this usage pattern is safe? It appears to work fine in clang and gcc.

#include <iomanip>
#include <iostream>
#include <sstream>

using namespace std;

ostringstream& make_string_impl(ostringstream&& s) { return s; }

template<typename T, typename... Ts>
ostringstream& make_string_impl(ostringstream&& s, T&& t, Ts&&... ts) {
    s << t;
    return make_string_impl(std::move(s), std::forward<Ts>(ts)...);
}

template<typename... Ts>
string make_string(Ts&&... ts) {
    return make_string_impl(ostringstream{}, std::forward<Ts>(ts)...).str();
}

int main() {
    cout << make_string("Hello, ", 5, " World!", '\n', 10.0, "\n0x", hex, 15, "\n");
}
like image 216
mattnewport Avatar asked Nov 07 '14 03:11

mattnewport


People also ask

What is a lifetime in c++?

C/C++ use lexical scoping. The lifetime of a variable or object is the time period in which the variable/object has valid memory. Lifetime is also called "allocation method" or "storage duration."

What is lifetime of a local object?

The lifetime of a variable is the time during which the variable stays in memory and is therefore accessible during program execution. The variables that are local to a method are created the moment the method is activated (exactly as formal parameters) and are destroyed when the activation of the method terminates.

How can you extend the lifetime of an object?

The lifetime of a temporary object may be extended by binding to a const lvalue reference or to an rvalue reference (since C++11), see reference initialization for details.

What is the lifetime of local object in C Plus Plus?

The lifetime of an object begins when its initialization is complete, and ends when its storage is released. Dynamic storage duration starts when the storage created by (new Type) is initialized, and ends when the object goes out of scope or is deleted by “delete pointer”.


1 Answers

The relevant part of the standard is in §12.2:

12.2.3) Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created.

Except:

12.2.4) There are two contexts in which temporaries are destroyed at a different point than the end of the full-expression. The first context is when a default construct is called to initialize an element of an array. ... [doesn't apply]

12.2.5) 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 of a subobject to which the reference is bound persists for the lifetime of the reference except:

  • ...

  • 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.

So there you go. The temporary stringstream{} is bound to a reference in a function call, so it persists until the completion of the expression. This is safe.

like image 88
Barry Avatar answered Sep 28 '22 07:09

Barry