This is just a comment, but too long to fit into the comment section. So I post it as an answer.
First lets look at the standard, it says
u
can, upon request, transfer ownership to another unique pointer u2
. Upon completion of
such a transfer, the following postconditions hold:
(4.1) — u2.p
is equal to the pre-transfer u.p
,
(4.2) — u.p
is equal to nullptr
, and
(4.3) — if the pre-transfer u.d
maintained state, such state has been transferred to u2.d
.
As in the case of a reset, u2
must properly dispose of its pre-transfer owned object via the pre-transfer
associated deleter before the ownership transfer is considered complete.
The standard only specified the behavior after the reset, the exact behavior during reset is implementation-dependent.
Then let's look at the GNU implementation:
void reset(pointer __p) noexcept
{
const pointer __old_p = _M_ptr();
_M_ptr() = __p;
if (__old_p)
_M_deleter()(__old_p);
}
~unique_ptr() noexcept
{
static_assert(...);
auto& __ptr = _M_t._M_ptr();
if (__ptr != nullptr)
get_deleter()(std::move(__ptr));
__ptr = pointer();
}
Which looks quite odd because the exact order are different in reset
and dtor. It doesn't make sense to me, until I read the MSVC implementation:
void reset(pointer _Ptr = nullptr) noexcept {
pointer _Old = _STD exchange(_Mypair._Myval2, _Ptr);
if (_Old) {
_Mypair._Get_first()(_Old);
}
}
When reset
, of course we need to swap current pointer with the argument. Also, don't forget to call the deleter. Simple job.
~unique_ptr() noexcept {
if (_Mypair._Myval2) {
_Mypair._Get_first()(_Mypair._Myval2);
}
}
In destructor, Microsoft doesn't bother set the pointer to nullptr
, they just call the deleter. Simple.
If you really want to set the pointer to nullptr
, I bet you will set it after you call the deleter.
Conclusion:
I don't think the STL authors really want to "prevent" you doing something. They just simply write the most straight-forward code to implement the requirement.