将 shared_ptr 指针指向一个数组 : 这样使用它好吗 ?

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

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

shared_ptr sp(new int[10]);

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

116978 次浏览

使用c++ 17shared_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);

要求: Y是一个完整类型。表达式delete[] p(当T是数组类型时)或delete p(当T不是数组类型时)必须具有定义良好的行为,且不得抛出异常 …
备注:T是数组类型时,此构造函数不应参与重载解析,除非表达式delete[] p是格式良好的,并且TU[N]Y(*)[N]可转换为T*,或者TU[]Y(*)[]可转换为T*. ...

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

using element_type = remove_extent_t<T>;

数组元素可以使用operator[]访问

  element_type& operator[](ptrdiff_t i) const;
< p > 要求: get() != 0 && i >= 0。如果TU[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[]>());
    
  • a lambda expression

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

Also, unless you actually need share onwership of the managed object, a unique_ptr is better suited for this task, since it has a partial specialization for array types.

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

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

另一个在c++ 17之前的替代方法是由图书馆基础技术规范提供的,它扩展了shared_ptr,以允许它在拥有对象数组的情况下开箱即用。针对此TS的shared_ptr更改的当前草案可以在N4082中找到。这些更改将通过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);

delete[] p5: Y应该是一个完整类型。表达式delete[] p(当T是数组类型时)或delete p(当T不是数组类型时)必须是格式良好的,必须具有定义良好的行为,并且不得抛出异常。当TU[N]时,Y(*)[N]应可转换为T*;当Tdelete[] p0时,delete[] p1应可转换为T*;否则,delete[] p3将转换为T*

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