C++ 唯一所有权(std :: unique_ptr)

示例

C ++ 11

Astd::unique_ptr是一个类模板,它管理动态存储的对象的生存期。对于不同std::shared_ptr的动态对象由只拥有一个实例的std::unique_ptr在任何时间,


// 创建一个由唯一指针拥有的值为20的动态int
std::unique_ptr<int> ptr = std::make_unique<int>(20);

(注意:std::unique_ptr自C ++ 11和std::make_uniqueC ++ 14起可用。)

只有变量ptr拥有指向动态分配的的指针int。当拥有一个对象的唯一指针超出范围时,将删除拥有的对象,即,如果对象属于类类型,则调用其析构函数,并释放该对象的内存。

要使用std::unique_ptr和std::make_unique用数组类型,利用自己的专长阵:

// 创建一个int值为59的unique_ptr
std::unique_ptr<int> ptr = std::make_unique<int>(59);

// 创建一个由15个整数组成的数组的unique_ptr
std::unique_ptr<int[]> ptr = std::make_unique<int[]>(15);

您可以std::unique_ptr像访问原始指针一样访问,因为它会使那些运算符过载。


您可以通过使用std::move将智能指针的内容的所有权转移到另一个指针,这将导致原始智能指针指向nullptr。

// 1. std :: unique_ptr
std::unique_ptr<int> ptr = std::make_unique<int>();

// 将值更改为1
*ptr = 1;

// 2. std :: unique_ptr(通过将“ ptr”移至“ ptr2”,“ ptr”不再拥有该对象)
std::unique_ptr<int> ptr2 = std::move(ptr);

int a = *ptr2; // 'a'是1
int b = *ptr;  //未定义的行为!'ptr'是'nullptr'
               // (由于上面的move命令)

传递unique_ptr给函数作为参数:

void foo(std::unique_ptr<int> ptr)
{
    // 您的代码在这里
}

std::unique_ptr<int> ptr = std::make_unique<int>(59);
foo(std::move(ptr))

unique_ptr从函数返回。这是编写工厂函数的首选C ++ 11方法,因为它清楚地传达了返回的所有权语义:调用者拥有结果unique_ptr并对其负责。

std::unique_ptr<int> foo()
{
    std::unique_ptr<int> ptr = std::make_unique<int>(59);
    return ptr;
}

std::unique_ptr<int> ptr = foo();

比较一下:

int* foo_cpp03();

int* p = foo_cpp03(); //我拥有p吗?我必须在某个时候删除它吗?
                      // 答案还不清楚。
C ++ 14

make_unique从C ++ 14开始提供类模板。将其手动添加到C ++ 11代码很容易:

template<typename T, typename... Args>
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
make_unique(Args&&... args)
{ return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); }

// 对数组使用make_unique
template<typename T>
typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T>>::type
make_unique(size_t n)
{ return std::unique_ptr<T>(new typename std::remove_extent<T>::type[n]()); }
C ++ 11

不同于智能指针(std::auto_ptr),unique_ptr也可与载体分配(实例化 std::vector)。较早的示例是标量分配。例如,要为10个元素动态分配一个整数数组,可以将其指定int[]为模板类型(而不仅仅是int):

std::unique_ptr<int[]> arr_ptr = std::make_unique<int[]>(10);

可以简化为:

auto arr_ptr = std::make_unique<int[]>(10);

现在,arr_ptr就像使用数组一样使用:

arr_ptr[2] =  10; // 修改第三个元素

您不必担心取消分配。此模板专用版本会适当地调用构造函数和析构函数。使用unique_ptr或vector本身的向量版本-是个人选择。

在C ++ 11之前的版本std::auto_ptr中可用。unique_ptr与之不同的是,它允许复制auto_ptrs,源ptr将在此上丢失所包含指针的所有权,而目标将接收它。