Search code examples
c++c++11rvalue-referenceobject-lifetimetemporary-objects

Lifetime extension and the conditional operator


local lvalue references-to-const and rvalue references can extend the lifetime of temporaries:

const std::string& a = std::string("hello");
std::string&& b = std::string("world");

Does that also work when the initializer is not a simple expression, but uses the conditional operator?

std::string&& c = condition ? std::string("hello") : std::string("world");

What if one of the results is a temporary object, but the other one isn't?

std::string d = "hello";
const std::string& e = condition ? d : std::string("world");

Does C++ mandate the lifetime of the temporary be extended when the condition is false?

The question came up while answering this question about non-copyable objects.


Solution

  • Both of those are fine.

    §5.16 says (extraordinarily abridged):

    2 If either the second or the third operand has type void

    Nope.

    3 Otherwise, if the second and third operand have different types

    Nope.

    4 If the second and third operands are glvalues of the same value category

    Nope. (In the first, both are prvalues and in the second one is a glvalue and one is a prvalue.)

    5 Otherwise, the result is a prvalue

    Okay, so both of these result in prvalues. So the binding is fine, but what's the binding to?

    6 Lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are per- formed on the second and third operands.

    Okay, so both are now rvalues if they weren't already.

    6 (continued) After those conversions, one of the following shall hold:

    The second and third operands have the same type; the result is of that type. If the operands have class type, the result is a prvalue temporary of the result type, which is copy-initialized from either the second operand or the third operand depending on the value of the first operand.

    Okay, so it's either std::string(first_operand) or std::string(second_operand).

    Regardless, the result of the conditional expression is a new prvalue temporary, and it's that value that's extended by binding to your references.