【问题标题】:How to declare std::unique_ptr and what is the use of it?如何声明 std::unique_ptr 以及它的用途是什么?
【发布时间】:2013-05-29 11:10:48
【问题描述】:

我试图了解std::unique_ptr 的工作原理,为此我找到了this 文档。作者从下面的例子开始:

#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);

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

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

【问题讨论】:

  • new int(3) 返回一个指向新int 的指针,就像pd 是一个指向新double 的指针一样。
  • unique_ptr 声明位于&lt;memory&gt; 而不是&lt;utility&gt;

标签: c++ pointers std unique-ptr


【解决方案1】:

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

在第一个例子中:

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

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

unique_ptr<double> uptr2 (pd);

指针存储在pd 变量中。

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

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是不可复制的。

只要您以不违反它们要求您遵守的隐含合同的方式使用智能指针,您就可以保证不会泄漏任何内存,并且将为您的对象执行适当的所有权政策.原始指针不提供这种保证。

【讨论】:

  • 嗨,我对model object ownership、代码中的integer leakenforcing ownership policy for object 一无所知。您能否建议学习这些概念的主题/资源?
  • 我无法使用unique_ptr,而不会出现错误:The text "&gt;" 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 &lt;utility&gt;#include &lt;memory&gt;。有什么建议吗?
【解决方案2】:

在分配给 unique_ptr 的两个概念中工作没有区别。

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

类似于

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

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


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

如果您在堆空间中创建一个整数(使用 new 关键字或 malloc),那么您必须自己清除该内存(使用 delete 免费)。

在下面的代码中,

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

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

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

【讨论】:

    【解决方案3】:

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

    在这种情况下:

    unique_ptr<double> uptr2 (pd);
    

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

    unique_ptr&lt;int&gt; uptr (new int(3)); 的情况并没有什么不同,只是这里的原始指针没有分配给任何变量。

    【讨论】:

      【解决方案4】:

      来自cppreferencestd::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;
      

      当你不再需要它或者它会导致内存泄漏时。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-09
        • 2022-01-31
        • 2017-06-05
        • 2010-12-13
        • 1970-01-01
        • 1970-01-01
        • 2012-09-17
        相关资源
        最近更新 更多