我理解unique_ptr
是某个对象的唯一所有者,并且在其超出范围时释放该对象。但我不明白以下情况:
unique_ptr<int> p(new int(1));
p = unique_ptr<int>(new int(2));
如果将指针
p
重定向到另一个内存位置 new int(2)
(因为 p
只能拥有其中之一),那么第一个对象 new int(1)
会发生什么?请注意,保留了 HTML 标签。我理解unique_ptr
是某个对象的唯一所有者,并且在其超出范围时释放该对象。但我不明白以下情况:
unique_ptr<int> p(new int(1));
p = unique_ptr<int>(new int(2));
p
重定向到另一个内存位置 new int(2)
(因为 p
只能拥有其中之一),那么第一个对象 new int(1)
会发生什么?请注意,保留了 HTML 标签。unique_ptr
是一种智能指针,当unique_ptr
被销毁或重新赋值时,它所拥有的对象也会被销毁。例如:
#include <iostream>
#include <memory>
using namespace std;
struct T {
T(int x) : x(x) {
cout << "T(" << x << ")\n";
}
~T() {
cout << "~T(" << x << ")\n";
}
int x;
};
int main() {
unique_ptr<T> p(new T(1));
p = unique_ptr<T>(new T(2));
}
这将打印:
T(1)
。T(2)
。p
的第一个对象时,打印~T(1)
。p
的第二个对象时,打印~T(2)
。p
的赋值运算符销毁了T(1)
,在这种情况下会发生什么?unique_ptr<T> p(new T(1)); unique_ptr<T> p2(new T(2)); p2 = move(p);
谁销毁了new T(2)
? - Tracerp2
被分配时,它所做的事情。 - GManNickGp2
的移动赋值运算符在从 p
移动 new T(1)
到 p2
之前必须销毁 new T(2)
。 - Jon Purdyp
被移动了。 - MSaltersnoexcept
的。§20.7.1¶3说:“让符号u.p
表示由u
存储的指针,让u.d
表示相关的删除器。在请求时,u
可以重置(替换)u.p
和u.d
为另一个指针和删除器,但必须通过相关的删除器正确处理其拥有的对象,然后才能认为完成了这种替换。” - Jon Purdyunique_ptr
被定义为确保第一个int得到正确地释放,因此它会调用delete
来释放已保留的内存。
这与下面的代码有些相似:
int* p = new int(1);
delete p;
p = new int(2);
new int(1)
创建一个新的整数。unique_ptr
实例,名为p
。这是一个暂时只存储指针的对象。new int(2)
创建第二个int。unique_ptr<int>(new int(2))
将此指针传递给新的unique_ptr
。这是一个临时的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
为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);
}
unique_ptr
是像其他任何对象一样的对象,具有构造函数和析构函数。当调用p = unique_ptr
时,将调用p
的析构函数来清理内存。 - Tasp
的赋值运算符是在清理内存。虽然会调用析构函数,但它不是p
的析构函数,而是临时的unique_ptr
移动后所调用的析构函数。请留意这点区别。 - Benjamin Lindleyunique_ptr
的全部目的。 - Lightness Races in Orbit