Каковы различия между std :: move и unique_ptr :: reset?

За std::unique_ptrs p1 а также p2Каковы различия между std::move() а также std::unique_ptr::reset()?

p1 = std::move(p2);

p1.reset(p2.release());

10

Решение

Ответ должен быть очевиден из спецификации стандарта на перемещение в [unique.ptr.single.assign] / 2:

Последствия: Передача права собственности от u в *this как будто позвонив reset(u.release()) с последующим назначением из std::forward<D>(u.get_deleter()),

Ясно, что задание на перемещение не совпадает с reset(u.release()) потому что это делает что-то дополнительное.

Дополнительный эффект важен, без него вы можете получить неопределенное поведение с пользовательскими удалителями:

#include <cstdlib>
#include <memory>

struct deleter
{
bool use_free;
template<typename T>
void operator()(T* p) const
{
if (use_free)
{
p->~T();
std::free(p);
}
else
delete p;
}
};

int main()
{
std::unique_ptr<int, deleter> p1((int*)std::malloc(sizeof(int)), deleter{true});
std::unique_ptr<int, deleter> p2;
std::unique_ptr<int, deleter> p3;

p2 = std::move(p1);  // OK

p3.reset(p2.release());  // UNDEFINED BEHAVIOUR!
}
16

Другие решения

Первый способ предупредить вас, например, о несоответствии деструкторов. К тому же, release() это очень опасная функция, и ваш тривиальный пример верен, но многие другие применения — нет. Лучше просто никогда, никогда не использовать эту функцию.

5

Думаю, вторая версия может быть небезопасной. Это эквивалентно:

auto __tmp = p2.release();
p1.reset(__tmp);

Таким образом, если вызов std::unique_ptr::reset throws (что может иметь место в случае удаления бросков управляемого объекта), тогда у вас есть объект без ссылки, который никогда не будет уничтожен. В случае назначения перемещения, std::unique_ptr может (и должен) ждать фактического движения до p1Оригинальный объект был уничтожен должным образом.

Но обратите внимание, что это проблема только в том случае, если деструктор управляемого объекта может сгенерировать, что почти во всех случаях само по себе неверно, или если вы используете специальный удалитель, который может сгенерировать. Таким образом, на практике обычно нет никаких поведенческих различий между двумя фрагментами кода.


РЕДАКТИРОВАТЬ: В конце Джонатан в своем комментарии указывает на то, что стандартное средство удаления требует от пользователя не выбрасывать, что действительно делает std::unique_ptr::reset довольно маловероятно / не соответствует. Но он также указывает на то, что есть еще одно отличие в том, что только назначение перемещения также перемещает любые пользовательские средства удаления, для которых он также написал ответ.


Но если не учитывать фактическое поведение, между ними существует огромная концептуальная разница. Если назначение перемещения подходит, затем сделайте задание на перемещение и постарайтесь не эмулировать его другим кодом. На самом деле я не могу представить себе причину заменить первый фрагмент кода один на один вторым. DeadMG прав в этом std::unique_ptr::release следует использовать, только если вы действительно знаете, что делаете и в каком контексте вы связываетесь с неуправляемыми динамическими объектами.

-2
По вопросам рекламы [email protected]