unique_ptr
определен, чтобы убедиться, что первый int правильно освобожден, поэтому он вызывает на нем delete
, освобождая зарезервированную память.
Это несколько идентична этому коду:
int* p = new int(1);
delete p;
p = new int(2);
Что происходит в деталях заключается в следующем:
- создается новый Integer с помощью
new int(1)
.
- Вы передаете указатель на этот новый int только что созданному экземпляру
unique_ptr
с именем p
. Это объект, который просто сохраняет указатель на данный момент.
- Вы создаете второй int, используя
new int(2)
.
- Вы передаете этот указатель новому
unique_ptr
, используя unique_ptr<int>(new int(2))
, это временный экземпляр unique_ptr (мы увидим, почему в секунду), и он сохранит указатель на второй int.
- Вы назначаете временный объект
p
. Теперь оператор присваивания определяется для удаления ранее принадлежащего ему объекта (первого int) и получения права собственности на объект, принадлежащий присвоенному unique_ptr (второй int). Ниже приведена реализация. На этом этапе p
владеет вторым int, первый int удаляется, а у временного больше нет объекта (удерживая nullptr
).
- В качестве последней части временный
unique_ptr
выходит за пределы области видимости, так как мы никогда не давали ему имени или не хранили ссылку на него, поэтому его деструктор вызывается. Но он все равно содержит nullptr
.
Таким образом, более подробный эквивалент с использованием сырых указателей будет что-то вроде этого:
int* p = new int(1); //create an int
{
int* tmp = new int(2); //create second int
int* del = p; //we need to delete this (first int)
//take ownership of the temporary (second int)
p = tmp;
tmp=nullptr;
//delete the old object (first int)
delete del;
} //tmp and del go out of scope here, but tmp holds the nullptr and del is deleted
//first int is deleted, p points to the second int here
Edit для Tracer: Это реализация используется Visual Studio (комментарий является частью <memory>
, как а):
typedef unique_ptr<_Ty> _Myt;
_Myt& operator=(_Myt&& _Right) _NOEXCEPT
{ // assign by moving _Right
if (this != &_Right)
{ // different, do the move
reset(_Right.release());
this->get_deleter() = _STD forward<_Dx>(_Right.get_deleter());
}
return (*this);
}
void reset(pointer _Ptr = pointer()) _NOEXCEPT
{ // establish new pointer
pointer _Old = get();
this->_Myptr() = _Ptr;
if (_Old != pointer())
this->get_deleter()(_Old);
}
Это потеряно, ушло навсегда, но гарантировано, что оно будет очищено должным образом. Если тип не является POD, его деструктор будет вызываться (если не используется какой-либо пользовательский деаллокатор). – Tas
Вот чего я не понимаю. Кто его убережет, так как он никому не принадлежит? – Tracer
'unique_ptr' - это объект, как любой другой, с конструктором и деструктором. Когда вызывается 'p = unique_ptr', вызывается деструктор для' p', который очищает память. – Tas