Ternary operator and prolonging the lifetime of a temporary object via reference-to-const

c++, c++11, copy-constructor, temporary-objects

Solution

No, it's not well-behaved. For the lifetime extension to occur, the temporary must be bound directly to the reference. Once you add a cast, the binding is no longer direct, and the resulting reference becomes dangling.

We can see this with some simple testing code:

#include <iostream>
struct Gizmo
{
    ~Gizmo() { std::cout << "Gizmo destroyed\n"; }
};

Gizmo Frobnicate(const Gizmo& arg) { return arg; }

void ProcessGizmo(const Gizmo& arg, bool frobnicate)
{
    const Gizmo& local = frobnicate ? static_cast<const Gizmo&>(Frobnicate(arg)) : arg;
    // Perform some work on local
    (void) local;
    std::cout << "Processing\n";
}

int main(){
    Gizmo g;
    ProcessGizmo(g, true);
    std::cout << "Processed\n";
}

This prints:

Gizmo destroyed
Processing
Processed
Gizmo destroyed

That first `Gizmo destroyed` message is from the return value of `Frobnicate()`; it's being destroyed at the end of that line - without lifetime extension.

An obvious workaround is moving the processing into another function:

void DoProcessGizmo(const Gizmo& arg) { /* process the Gizmo */ }

void ProcessGizmo(const Gizmo& arg, bool frobnicate)
{
    return frobnicate ? DoProcessGizmo(Frobnicate(arg)) : DoProcessGizmo(arg);
}

Problem

After seeing that a local reference-to-const may prolong the life of a temporary, I encountered the need to conditionally bind a local reference-to-const to either a function parameter or the temporary result of a function call, i.e.: ``` class Gizmo { // Rule of Five members implemented }; Gizmo Frobnicate(const Gizmo& arg); void ProcessGizmo(const Gizmo& arg, bool frobnicate) { const Foo& local = frobnicate ? Frobnicate(arg) : arg; // Perform some work on local } ``` A practical example: the boolean specifies whether to compress a buffer and you'd like to write uniform code that operates on `local` either way. The above example, however, invoked Gizmo's copy-constructor on `arg` when `frobnicate` was `false`. I managed to avoid the invocation of the copy-constructor by changing `Frobnicate(arg)` to `static_cast<const Gizmo&>(Frobnicate(arg))`. My question becomes: how does the ternary operator interact with the rule about binding a local reference-to-const to a temporary? Is my solution legal and well-behaved?

Original source

Related problems