为什么我不能在smart_pointers中使用`new []`?

时间:2015-08-15 11:17:40

标签: c++11 stl smart-pointers

为什么我不能将new [ ]与smart_poin一起使用?

实际上我无法理解这段文字。

  

警告您应该仅为auto_prt或shared_ptr对象使用   由new分配的内存,而不是new []分配的内存。您   不应该使用auto_ptr,shared_ptr或orunique_ptr作为内存   通过new分配,或者在unique_ptr的情况下,通过new或new []分配。

2 个答案:

答案 0 :(得分:5)

  

为什么我不能将new[]与智能指针一起使用?

通常你可以,但智能指针必须知道它存储动态分配的数组而不是单个对象的事实。这是因为分配了运算符new[]的对象应该使用运算符delete[]而不是 delete取消分配。智能指针如何知道应该应用哪个运算符?

通过为数组类型提供智能指针类模板的特殊化来实现区别,就像目前在std::unique_ptr<T>中完成的那样:

std::unique_ptr<int> ptr(new int);      // will call delete
std::unique_ptr<int[]> arr(new int[5]); // will call delete[]
                   ↑↑

DEMO

但是,该语法(尚未)适用于标准库中可用的所有智能指针类型。

为了进行比较,Boost Smart Pointers库提供了单独的类模板,用于存储指向动态分配的数组的指针:

boost::shared_array<int> arr1(new int[5]); // will call delete[]
//            ~~~~^
boost::scoped_array<int> arr2(new int[5]); // will call delete[]
//            ~~~~^

DEMO 2

  

您应该仅将auto_ptrshared_ptr对象用于由new分配的内存,而不应用于由new []分配的内存。

std::auto_ptr<T>(†2017) 1 将普通delete运算符应用于它存储的指针,并且无法更改该行为。因此,存储指向数组的指针不是一种选择。

std::shared_ptr<T>而言,默认情况下它会做同样的事情(调用operator delete)。要更改该行为并正确释放存储阵列的内存区域,可以使用自定义删除器,如std::default_delete<T[]>

std::shared_ptr<int> arr(new int[5], std::default_delete<int[]>{});
                                                            ↑↑

或您自己提供的其他一些内容:

std::shared_ptr<int> arr(new int[5], [](int* ptr) { delete[] ptr; } );
//                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

DEMO 3

但是,std::shared_ptr<T[]>缺少专业化意味着没有operator[]可以让您轻松访问存储数组的元素,从而导致语法不正确,如arr.get()[0]

引入了提案N4077数组类型指针的专门化:

std::shared_ptr<int[]> arr(new int[5]); // will call delete[]
                   ↑↑
  

您不应将auto_ptrshared_ptrunique_ptr用于未通过new分配的内存,或者在unique_ptr的情况下,通过newnew[]

此摘录简单地指出,不应该从指向未动态分配的对象的指针构造智能指针,因为(默认情况下)它会导致在未分配{的内容上调用delete {1}}(同上new / new[])。

  

delete[]unique_ptr<double[]> p1(new double[2]);unique_ptr<double> p2(new double[2]);之间的区别是什么?

  1. unique_ptr<double[]> p3(new double(2));
  2. 确定:从两个std::unique_ptr<double[]> p1(new double[2]);数组的指针构造unique_ptr(并获得所有权)。它将调用double来释放指向的内存。

    1. delete[]
    2. 错误:从两个std::unique_ptr<double> p2(new double[2]);数组的指针构造一个unique_ptr(并获得所有权)。它将调用double(!)来释放指向的内存。 (可能是未定义的行为 - deletenew[]之间的不匹配。)

      1. delete
      2. 错误:从std::unique_ptr<double[]> p3(new double(2));构建一个指向 unique_ptr的指针(并获得所有权),该指针已初始化为值{{1} }。它将调用double(!)来释放指向的内存。 (可能是未定义的行为 - 2delete[]之间的不匹配。)

        自p ++ 11以来,

        1 new被视为不赞成delete[],并且将根据{{从C ++ 1z中的标准库中删除3}}

答案 1 :(得分:1)

<强>示例:

#include <memory>

int
main()
{
    auto p1 = std::unique_ptr<char[]>{new char[3]};  // C++11
    auto p2 = std::shared_ptr<char>{new char[3], [](char* p) {delete [] p;}}; // C++11
    auto p3 = std::make_unique<char[]>(3);           // C++14
}

第一个和第二个适用于C ++ 11和转发。第3版是在C ++ 14中引入的。第一个和第三个代表新的唯一所有权,第二个拥有新的所有权。