如何声明std :: unique_ptr,它的用途是什么?


95

我尝试了解其std::unique_ptr工作原理,并为此找到了文档。作者从以下示例开始:

#include <utility>  //declarations of unique_ptr
using std::unique_ptr;
// default construction
unique_ptr<int> up; //creates an empty object
// initialize with an argument
unique_ptr<int> uptr (new int(3));
double *pd= new double;
unique_ptr<double> uptr2 (pd);
// overloaded * and ->
*uptr2 = 23.5;
unique_ptr<std::string> ups (new std::string("hello"));
int len=ups->size();

让我感到困惑的是

unique_ptr<int> uptr (new int(3));

我们使用整数作为参数(在圆括号之间),这里

unique_ptr<double> uptr2 (pd);

我们使用了指针作为参数。有什么区别吗?

对我来说还不清楚的是,以这种方式声明的指针与以“正常”方式声明的指针有何不同。


13
new int(3)返回指向新指针的指针int,就像pd指向新指针的指针一样double
David Schwartz 2013年

Answers:


89

的构造函数unique_ptr<T>接受指向类型对象的原始指针T(因此,它接受T*)。

在第一个示例中:

unique_ptr<int> uptr (new int(3));

指针是new表达式的结果,而在第二个示例中:

unique_ptr<double> uptr2 (pd);

指针存储在 pd变量中。

从概念上讲,没有任何变化(您正在unique_ptr从原始指针构造a ),但是第二种方法可能更危险,因为它可以使您执行以下操作:

unique_ptr<double> uptr2 (pd);
// ...
unique_ptr<double> uptr3 (pd);

因此,具有两个有效封装相同对象的唯一指针(从而违反了唯一指针的语义)。

这就是为什么在可能的情况下,用于创建唯一指针的第一种形式会更好的原因。注意,在C ++ 14中,我们将能够做到:

unique_ptr<int> p = make_unique<int>(42);

这既清楚又安全。现在关于您的这个疑问:

对我来说还不清楚的是,以这种方式声明的指针与以“正常”方式声明的指针有何不同。

智能指针应该用于对对象所有权进行建模,并在指向该对象的最后一个(智能,拥有)指针超出范围时自动负责销毁该对象。

这样,您不必记住delete对动态分配的对象执行操作(智能指针的析构函数将为您完成此操作),也不必担心您是否不会将(悬挂的)指针取消引用到已被破坏的对象:

{
    unique_ptr<int> p = make_unique<int>(42);
    // Going out of scope...
}
// I did not leak my integer here! The destructor of unique_ptr called delete

现在unique_ptr是一个建模唯一所有权的智能指针,这意味着在程序中的任何时候都将只有一个(拥有)指向该指向对象的指针-这unique_ptr就是不可复制的原因。

只要您以不破坏要求它们遵守的隐式契约的方式使用智能指针,就可以保证不会泄漏任何内存,并且将强制执行针对对象的正确所有权策略。原始指针不会给您这种保证。


3
嗨,我无法理解任何事情model object ownership,该integer leak代码或enforcing ownership policy for object。您能否建议一些主题/资源来学习这些概念?
乌冬之焰

1
我不能使用unique_ptr,没有得到一个错误:The text ">" is unexpected. It may be that this token was intended as a template argument list terminator but the name is not known to be a template.,即使我有#include <utility>#include <memory>。有什么建议吗?
匿名

15

分配给unique_ptr的两个概念都没有区别。

int* intPtr = new int(3);
unique_ptr<int> uptr (intPtr);

类似于

unique_ptr<int> uptr (new int(3));

在这里unique_ptr会自动删除占用的空间uptr


以这种方式声明的指针与以“正常”方式声明的指针的方式将有所不同。

如果在堆空间中创建一个整数(使用new关键字或malloc),则必须自行清除该内存(分别使用deletefree)。

在下面的代码中,

int* heapInt = new int(5);//initialize int in heap memory
.
.//use heapInt
.
delete heapInt;

使用完后,您必须在这里删除heapInt。如果未删除,则会发生内存泄漏。

为了避免此类内存泄漏,使用unique_ptr,其中unique_ptr会在超出范围时自动删除heapInt占用的空间。因此,您无需为unique_ptr删除释放它


10

当唯一指针超出范围时,可以保证销毁它们管理的对象。 http://en.cppreference.com/w/cpp/memory/unique_ptr

在这种情况下:

unique_ptr<double> uptr2 (pd);

pduptr2超出范围时将被销毁。这有助于通过自动删除来进行内存管理。

的情况unique_ptr<int> uptr (new int(3));没有什么不同,只不过这里未将原始指针分配给任何变量。


-1

cppreference中std::unique_ptr构造函数之一是

显式unique_ptr(指针p)noexcept;

因此,创建新对象std::unique_ptr是将指针传递给其构造函数。

unique_ptr<int> uptr (new int(3));

或与

int *int_ptr = new int(3);
std::unique_ptr<int> uptr (int_ptr);

区别在于您无需在使用后清理。如果您不使用std::unique_ptr(智能指针),则必须像这样删除它

delete int_ptr;

当您不再需要它时,否则将导致内存泄漏。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.