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

Why can not I use `new [ ]` with smart_pointers?

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

其实这段文字我看不懂

Caution You should use an auto_prt or shared_ptr object only for memory allocated by new, not for memory allocated by new []. You should not use auto_ptr, shared_ptr,orunique_ptr for memory not allocated via new or, in the case of unique_ptr, via new or new[].

示例:

#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 及更高版本。第三个是在 C++14 中引入的。第一个和第三个代表新的唯一所有权,第二个代表新的共享所有权。

Why can not I use new[] with smart pointers?

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

通过为数组类型提供智能指针 class 模板的专门化来区分,就像目前在 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 库提供了单独的 class 模板,用于存储指向动态分配数组的指针:

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

DEMO 2


You should use an auto_ptr or shared_ptr object only for memory allocated by new, not for memory allocated by new [].

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

std::shared_ptr<T> is concerned, by default it does the same (calls operator delete). To change that behavior, and properly deallocate a memory area of a stored array, you could use a custom deleter, like 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[]
                   ↑↑

You should not use auto_ptr, shared_ptr, or unique_ptr for memory not allocated via new or, in the case of unique_ptr, via new or new[].

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


What is the difference between unique_ptr<double[]> p1(new double[2]);, unique_ptr<double> p2(new double[2]);, unique_ptr<double[]> p3(new double(2)); ?

  1. std::unique_ptr<double[]> p1(new double[2]);

OK:从指向两个 double秒。它将调用 delete[] 来释放指向的内存。

  1. std::unique_ptr<double> p2(new double[2]);

错误:从指向两个 double秒。它将调用 delete (!) 来释放指向的内存。 (可能是未定义的行为 - new[]delete 之间的不匹配)。

  1. std::unique_ptr<double[]> p3(new double(2));

错误:从指向 single [=48= 的指针(并取得所有权)构造 unique_ptr ] 初始化为值 2。它将调用 delete[] (!) 来释放指向的内存。 (可能是未定义的行为 - newdelete[] 之间的不匹配)。


1 std::auto_ptr<T> 自 C++11 起被弃用,取而代之的是 std::unique_ptr<T>,并将从 C++ 的标准库中删除1z 根据 N4168.