I have recently found out about replacing:
std::shared_ptr<NEWT>(static_cast<NEWT>(old_ptr.get()));
with
std::static_pointer_cast<NEWT>(odl_ptr);
I know that the former solution may result in double delete if one is not careful.
I was wondering if the reference counting is updated with the latter solution, and how is that achievable?
Using static_pointer_cast or dynamic_pointer_cast enables the generated shared_ptr to do proper reference counting without resulting in double deletes. This is achieved by calling a special constructor for the resulting casted pointer, here is an example implementation:
template< class T, class U >
std::shared_ptr<T> static_pointer_cast( const std::shared_ptr<U>& r ) noexcept
{
auto p = static_cast<typename std::shared_ptr<T>::element_type*>(r.get());
return std::shared_ptr<T>(r, p);
}
Notice that the constructor called is
std::shared_ptr<T>(r,p);
which actually is of the form
template< class Y >
shared_ptr( const shared_ptr<Y>& r, T *ptr );
The latter is an aliasing constructor, meaning that the object is managed by r, and the constructed shared_ptr is unamanaged. To have the same behaviour without the static_cast_pointer one would have to write
std::shared_ptr<T>(r, static_cast<T>(odl_ptr.get());
where your old_ptr is of some other type.
some code from here