unique_ptr的重点是什么?

时间:2015-01-20 00:42:36

标签: pointers c++11 memory unique-ptr

不是unique_ptr与对象的直接实例基本相同吗?我的意思是,动态继承和性能存在一些差异,但所有unique_ptr都有吗?

考虑一下这段代码,看看我的意思。不是这个:

#include <iostream>
#include <memory>

using namespace std;

void print(int a) {
    cout << a << "\n";
}

int main()
{
   unique_ptr<int> a(new int);
   print(*a);

   return 0;
}

几乎完全相同:

#include <iostream>
#include <memory>

using namespace std;

void print(int a) {
    cout << a << "\n";
}

int main()
{
   int a;
   print(a);

   return 0;
}

或者我误解了unique_ptr应该用于什么?

5 个答案:

答案 0 :(得分:4)

std::unique_ptr的目的是提供动态分配内存的自动和异常安全释放(与原始指针不同,原始指针必须明确delete d才能被释放且容易无意中在交错异常的情况下不会被释放。)

但是,你的问题更多地是关于指针的价值,而不是关于std::unique_ptr。对于像int这样的简单内置类型,通常没有理由使用指针而不是简单地按值传递或存储对象。但是,有三种情况需要指针:

  1. 代表单独的“未设置”或“无效”值。
  2. 允许修改。
  3. 允许不同的多态运行时类型。
  4. 无效或未设置

    指针支持额外的nullptr值,表示尚未设置指针。例如,如果要支持给定类型的所有值(例如整个整数范围),但也表示用户从不在接口中输入值的概念,那么使用{{1}的情况就是这种情况。因为你可以得到指针是否为空,作为指示它是否被设置的方式(不必丢弃有效的整数值只是为了使用该特定值作为无效,“sentinel”值表示它没有设定。)

    允许修改

    这也可以通过引用而不是指针来完成,但指针是这样做的一种方式。如果您使用常规值,那么您正在处理原始副本,并且任何修改仅影响该副本。如果使用指针或引用,则可以将修改视为原始实例的所有者。使用唯一指针,您还可以确保没有其他人拥有副本,因此可以安全地进行修改而无需锁定。

    多态类型

    这同样可以通过引用来完成,而不仅仅是使用指针,但是在某些情况下,由于所有权或分配的语义,您可能希望使用指针来执行此操作...当涉及到用户定义的类型时,可以创建分层的“继承”关系。如果希望代码对给定类型的所有变体进行操作,则需要使用指针或对基类型的引用。将std::unique_ptr<int>用于此类事件的常见原因是,如果对象是通过工厂构造的,其中您定义的类维护构造对象的所有权。例如:

    std::unique_ptr<>

答案 1 :(得分:4)

正如您所提到的,虚拟类是一个用例。除此之外,还有两个:

  1. 对象的可选实例。我的类可能会延迟实例化对象的实例。为此,我需要使用内存分配,但仍然希望获得RAII的好处。

  2. 与喜欢返回裸指针的C库或其他库集成。例如,OpenSSL返回许多(记录不完整)方法的指针,其中一些方法需要清理。拥有一个不可复制的指针容器非常适合这种情况,因为我可以在返回后立即保护它。

答案 2 :(得分:4)

除了Chris Pitman提到的案例之外,如果你实例化足够大的对象,你还需要使用std::unique_ptr的另一个案例,那么在堆中而不是在堆栈上执行它是有意义的。堆栈大小不是无限制的,迟早你可能会遇到堆栈溢出。这就是std::unique_ptr有用的地方。

答案 3 :(得分:1)

unique_ptr的功能与普通指针的功能相同,只是你不必记住释放它(事实上它只是一个指针的包装器)。在分配内存之后,您不必在指针上调用delete,因为unique_ptr上的析构函数会为您处理此事。

答案 4 :(得分:0)

我想到了两件事:

  • 您可以将其用作通用的异常安全RAII包装器。任何具有“关闭”功能的资源都可以使用自定义删除器轻松地用unique_ptr包装。

  • 有时您可能必须移动指针而不明确知道其生命周期。如果您知道的唯一约束是唯一性,那么unique_ptr是一个简单的解决方案。在这种情况下,您几乎总是可以进行手动内存管理,但它不会自动异常安全,您可能会忘记delete。或者代码中delete的位置可能会发生变化。 unique_ptr解决方案可以更容易维护。