只是一个关于shared_ptr的小查询。

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

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

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


在c++ 17中,shared_ptr可以用来管理动态分配的数组。在本例中,shared_ptr模板参数必须为T[N]或T[]。所以你可以写

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

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

template<class Y> explicit shared_ptr(Y* p); Requires: Y shall be a complete type. The expression delete[] p, when T is an array type, or delete p, when T is not an array type, shall have well-defined behavior, and shall not throw exceptions. ... Remarks: When T is an array type, this constructor shall not participate in overload resolution unless the expression delete[] p is well-formed and either T is U[N] and Y(*)[N] is convertible to T*, or T is U[] and Y(*)[] is convertible to T*. ...

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

using element_type = remove_extent_t<T>;

可以使用操作符[]访问数组元素

Element_type& operator[](ptrdiff_t i) const; 要求:get() != 0 && i >= 0。如果T是U[N], i < N。 ... 备注:当T不是数组类型时,不指定是否声明该成员函数。如果声明了,则没有指明其返回类型是什么,除非函数的声明(尽管不一定是定义)必须是格式良好的。


在c++ 17之前,shared_ptr不能用于管理动态分配的数组。默认情况下,当不再有对托管对象的引用时,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;});

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

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

c++库基础扩展引入的变化

Another pre-C++17 alternative to the ones listed above was provided by the Library Fundamentals Technical Specification, which augmented shared_ptr to allow it to work out of the box for the cases when it owns an array of objects. The current draft of the shared_ptr changes slated for this TS can be found in N4082. These changes will be accessible via the std::experimental namespace, and included in the <experimental/memory> header. A few of the relevant changes to support shared_ptr for arrays are:

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

typedef T element_type; typedef typename remove_extent<T>::type element_type;

—正在添加成员操作符[]

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); 要求:Y为完整型。表达式delete[] p(当T是数组类型时)或delete p(当T不是数组类型时)应该是良好形式的,应该有良好定义的行为,并且不抛出异常。当T为U[N]时,Y(*)[N]可转换为T*;当T为U[]时,Y(*)[]可转换为T*;否则,Y*将转换为T*。


你可以使用的一个更简单的替代方法是shared_ptr<vector<int>>。