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?