小编典典

shared_ptr 到一个数组:应该使用它吗?

all

只是一个关于shared_ptr.

shared_ptr使用指向数组是一种好习惯吗?例如,

shared_ptr<int> sp(new int[10]);

如果不是,那为什么不呢?我已经知道的一个原因是不能增加/减少shared_ptr. 因此它不能像普通的指向数组的指针一样使用。


阅读 70

收藏
2022-07-12

共1个答案

小编典典

使用 C++17shared_ptr可用于管理动态分配的数组。在这种情况下,shared_ptr模板参数必须是T[N]or
T[]。所以你可以写

shared_ptr<int[]> sp(new int[10]);

从 n4659,[util.smartptr.shared.const]

  template<class Y> explicit shared_ptr(Y* p);

Requires: Y必须是一个完整的类型。表达式delete[] p, whenT是数组类型,或者delete p,
whenT不是数组类型,应具有明确定义的行为,并且不应抛出异常。

备注:T是数组类型时,此构造函数不应参与重载决议,除非表达式delete[] p是格式正确的并且要么TisU[N]并且Y(*)[N]可转换为T*,要么Tis
U[]并且Y(*)[]可转换为T*。…

为了支持这一点,成员类型element_type现在定义为

using element_type = remove_extent_t<T>;

数组元素可以使用operator[]

  element_type& operator[](ptrdiff_t i) const;

要求: get() != 0 && i >= 0。如果TU[N], i < N. …
备注:
T不是数组类型时,不指定是否声明该成员函数。如果它被声明,它的返回类型是什么是未指定的,除了函数的声明(虽然不一定是定义)应该是格式良好的。


在 C++17 之前* ,不能
用于shared_ptr管理动态分配的数组。默认情况下,当不再有对托管对象的引用时,将调用托管对象。但是,当您分配 using
时,您需要调用而不是调用来释放资源。
*shared_ptr``delete``new[]``delete[]``delete

为了正确使用shared_ptr数组,您必须提供自定义删除器。

template< typename T >
struct array_deleter
{
  void operator ()( T const * p)
  { 
    delete[] p; 
  }
};

创建 shared_ptr 如下:

std::shared_ptr<int> sp(new int[10], array_deleter<int>());

现在将在销毁托管对象时shared_ptr正确调用。delete[]

上面的自定义删除器可以替换为

  • std::default_delete数组类型的部分特化

    std::shared_ptr<int> sp(new int[10], std::default_delete<int[]>());
    
  • 一个 lambda 表达式

    std::shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });
    

此外,除非您确实需要托管对象的共享权限,否则 aunique_ptr更适合此任务,因为它具有数组类型的部分特化。

std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[]

C++ Extensions for Library Fundamentals 引入的变化

Library Fundamentals Technical
Specification
提供了上面列出的另一个
C++17
之前的替代方案,该规范对其进行了扩充shared_ptr,使其能够在拥有对象数组的情况下开箱即用。shared_ptr可在N4082中找到为此 TS
计划的当前更改草案。这些更改将可通过std::experimental命名空间访问,并包含在<experimental/memory>标头中。shared_ptr支持数组的一些相关更改是:

’ 成员类型的定义element_type发生变化

typedef T element_type;

 typedef typename remove_extent<T>::type element_type;

operator[]正在添加成员

 element_type& operator[](ptrdiff_t i) const noexcept;


unique_ptr数组的部分特化不同,两者shared_ptr<T[]>shared_ptr<T[N]>都是有效的,并且都将导致在delete[]对象的托管数组上被调用。

 template<class Y> explicit shared_ptr(Y* p);

Requires :Y应该是一个完整的类型。表达式delete[] p, whenT是数组类型,或者delete p,
whenT不是数组类型,应具有良好的格式,应具有良好定义的行为,并且不应抛出异常。T什么时候U[N],Y(*)[N]应转换为T*;
什么时候,应转换T为; 否则,应转换为.U[]``Y(*)[]``T*``Y*``T*

2022-07-12