mattnewport
mattnewport

Reputation: 14057

C++ lifetime of temporaries - is this safe?

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");
}

Upvotes: 11

Views: 451

Answers (1)

Barry
Barry

Reputation: 303087

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.

Upvotes: 7

Related Questions