clang
(libc ++) кажется несовместимым по этому вопросу, потому что стандарт гласит:
[unique.ptr.single.dtor]
~unique_ptr();
Требуется: Выражение get_deleter()(get())
должно быть правильно сформированным, иметь четко определенное поведение и не создавать исключений.
[ Примечание: Использование default_delete
требует, чтобы T
был полным типом.
- Конечная нота
]
Эффекты: если get() == nullptr
, то никаких эффектов нет.
В противном случае get_deleter()(get())
.
Таким образом, деструктор должен быть эквивалентен get_deleter()(get())
, что подразумевает, что b->a
не может быть nullptr
в деструкторе A
(который вызывается внутри get_deleter()
инструкцией delete
).
В примечании сторон, clang
(libc ++) и gcc
(libstdc ++) устанавливают указатель на nullptr
при уничтожении std::unique_ptr
, но деструктор gcc
:
auto& __ptr = _M_t._M_ptr();
if (__ptr != nullptr)
get_deleter()(__ptr);
__ptr = pointer();
... а вот clang
(вызов reset()
):
pointer __tmp = __ptr_.first();
__ptr_.first() = pointer();
if (__tmp)
__ptr_.second()(__tmp);
Как видите, gcc
сначала удаляет, затем присваивает nullptr
(pointer()
), тогда как clang
сначала присваивает nullptr
(pointer()
), затем удаляет 1 .
1 pointer
- псевдоним, соответствующий Deleter::pointer
, если он существует, или просто T*
.