为什么我不能将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
你应该只为new分配的内存使用auto_ptr或shared_ptr对象,而不是new []分配的内存。
std::auto_ptr<T>(† 2017)1 将普通的 delete 运算符应用于它存储的指针,并且无法更改该行为。因此,存储指向数组的指针不是一种选择。
就std::shared_ptr<T> 而言,默认情况下它的作用相同(调用运算符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_ptr、shared_ptr 或unique_ptr 来表示不是通过new 分配的内存,或者在unique_ptr 的情况下通过new 或new[] 分配的内存。
这段摘录只是说明不应从指向未动态分配的对象的指针构造智能指针,因为(默认情况下)它会导致在未分配 new 的对象上调用 delete (同上new[]/delete[])。
unique_ptr<double[]> p1(new double[2]);、unique_ptr<double> p2(new double[2]);、unique_ptr<double[]> p3(new double(2)); 有什么区别?
std::unique_ptr<double[]> p1(new double[2]);
OK:从两个doubles 的数组 的指针构造一个unique_ptr(并获得所有权)。它将调用delete[] 来释放指向的内存。
std::unique_ptr<double> p2(new double[2]);
错误:从一个指向两个doubles 的数组 的指针构造一个unique_ptr(并获得所有权)。它将调用delete (!) 来释放指向的内存。 (可能是未定义的行为 - new[] 和 delete 不匹配)。
std::unique_ptr<double[]> p3(new double(2));
错误:从一个指针构造一个unique_ptr(并取得其所有权),该指针指向一个初始化为值2的单个double。它将调用delete[] (!) 来释放指向的内存。 (可能是未定义的行为 - new 和 delete[] 不匹配)。
1std::auto_ptr<T> 自 C++11 起被视为已弃用,取而代之的是 std::unique_ptr<T>,并将根据 N4168 从 C++1z 中的标准库中删除。