This is something that came up recently and which I feel shouldn't work as it apparently does:
#include <iostream>
#include <memory>
int main()
{
std::shared_ptr<int>& ptr = const_cast<std::shared_ptr<int>&>(
static_cast<const std::shared_ptr<int>&>(
std::shared_ptr<int>(
new int(5), [](int* p) {std::cout << "Deleting!"; *p = 999; delete(p); }
)
)
);
std::cout << "I'm using a non-const ref to a temp! " << *ptr << " ";
}
The use of shared_ptr
isn't necessary here, but the custom deleter allows for an easy demonstration of the lifetime of the resulting object. There resulting output from Visual Studio, Clang and GCC is the same:
I'm using a non-const ref to a temp! 5 Deleting!
Meaning the lifetime of the resulting shared_ptr
has, through some mechanism, been extended to match that of the std::shared_ptr<int>& ptr
.
Now, I'm aware that the lifetime of a temporary will be extended to that of the reference for the case of a constant reference. But the only named object is a non-const reference, all other intermediate representations I would expect to have a lifetime equal only to the initialization expression.
Additionally, Microsoft have an extension which allows non-const references to extend the lifetime of a bound temporary, but this behaviour appears to be present even when that extension is disabled and, additionally, also appears in Clang and GCC.
According to this answer I believe the temporary is implicitly being created as const
, so attempting to modify the object referenced by ptr
is probably undefined behaviour, but I'm not sure that knowledge tells me anything about why the lifetime is being extended. My understanding is that it is the act of modifying a const that is UB, not simply taking a non-const reference to it.
My understanding of what should be happening is as follows:
Type()
creates a prvalue with no cv-specification.
static_cast<const Type&>(...)
materializes that prvalue into a const xvalue with a lifetime equal to the interior expression. We then create a const lvalue reference to that const xvalue. The lifetime of the xvalue is extended to match that of the const lvalue reference.
const_cast<Type&>(...)
produces an lvalue reference which is then assigned to ptr
. The const lvalue reference then expires, taking the materialized xvalue with it.
I try to read dangling reference ptr
and bad things happen.
What's wrong in my understanding? Why don't the bits in italics happen?
As an extra bonus question, am I correct in thinking that the underlying object is const, and that any attempt to modify it through this path will result in undefined behaviour?
In the by-reference case, we get a const Base& reference that refers to a Derived object. The entire temporary object, of type Derived , is lifetime-extended.
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.
A variable can be declared as a reference by putting '&' in the declaration. int i = 10; // Reference to i. References to pointers is a modifiable value that's used same as a normal pointer.
Because the reference is a const reference the function body cannot directly change the value of that object. This has a similar property to passing by value where the function body also cannot change the value of the object that was passed in, in this case because the parameter is a copy.
Any reference can extend the lifetime of an object. However, a non-const reference cannot bind to a temporary as in your example. The Microsoft extension you refer to is not "Extend lifetime by non-const references," rather "Let non-const references bind to temporaries." They have that extension for backward compatibility with their own previous broken compiler versions.
By a cast you have forced the binding of a non-const reference to a temporary, which does not appear to be invalid, just unusual because it cannot be done directly. Once you've accomplished that binding, lifetime extension occurs for your non-const reference the same as it would for a const reference.
More information: Do *non*-const references prolong the lives of temporaries?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With