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

tsh*_*h06 157 c++ shared-ptr c++11

只是一个小问题shared_ptr.

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

shared_ptr<int> sp(new int[10]);
Run Code Online (Sandbox Code Playgroud)

如果没有,那么为什么不呢?我已经意识到的一个原因是不能增加/减少shared_ptr.因此,它不能像正常指向数组的指针一样使用.

Pra*_*ian 243

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

shared_ptr<int[]> sp(new int[10]);
Run Code Online (Sandbox Code Playgroud)

来自n4659,[util.smartptr.shared.const]

  template<class Y> explicit shared_ptr(Y* p);
Run Code Online (Sandbox Code Playgroud)

要求: 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>;
Run Code Online (Sandbox Code Playgroud)

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

  element_type& operator[](ptrdiff_t i) const;
Run Code Online (Sandbox Code Playgroud)

要求: 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; 
  }
};
Run Code Online (Sandbox Code Playgroud)

创建shared_ptr,如下所示:

std::shared_ptr<int> sp(new int[10], array_deleter<int>());
Run Code Online (Sandbox Code Playgroud)

现在shared_ptrdelete[]在销毁托管对象时正确调用.

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

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

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

C++扩展库引入的更改

图书馆基础技术规范提供了另一种前C++ 17替代方案,它扩展shared_ptr到允许它在拥有一系列对象的情况下开箱即用.目前shared_ptr该TS 的变更草案可在N4082中找到.这些更改将通过std::experimental命名空间访问,并包含在<experimental/memory>标头中.支持shared_ptr数组的一些相关更改是:

- 成员类型的定义element_type更改

typedef T element_type;

 typedef typename remove_extent<T>::type element_type;
Run Code Online (Sandbox Code Playgroud)

- operator[]正在加入成员

 element_type& operator[](ptrdiff_t i) const noexcept;
Run Code Online (Sandbox Code Playgroud)

-不同于unique_ptr用于阵列部分特,都shared_ptr<T[]>shared_ptr<T[N]>将是有效的,都将导致delete[]被称为对象的管理的阵列上.

 template<class Y> explicit shared_ptr(Y* p);
Run Code Online (Sandbox Code Playgroud)

要求:Y应为完整类型.表达式delete[] p,当T是数组类型时,或者delete p,当T不是数组类型时,应该是格式良好的,应该具有良好定义的行为,并且不应抛出异常.如果TU[N],Y(*)[N]应转换为T*; 当TU[],Y(*)[]应转变成T*; 否则,Y*应可转换为T*.

  • ALT:`std :: shared_ptr <int> sp(new int [10],std :: default_delete <int []>());`另见http://en.cppreference.com/w/cpp/memory/ default_delete (52认同)
  • 为什么`unique_ptr`得到部分特化,但`shared_ptr`没有? (13认同)
  • +1,备注:还有Boost的[`shared-array`](http://www.boost.org/doc/libs/1_51_0/libs/smart_ptr/shared_array.htm). (7认同)
  • @tshah06 [`shared_ptr :: get`](http://en.cppreference.com/w/cpp/memory/shared_ptr/get)返回指向托管对象的指针.所以你可以用它作为`sp.get()[0] = 1; ... sp.get()[9] = 10;` (5认同)
  • @Jeremy如果在编译时已知大小,则无需为此编写类,`std :: shared_ptr <std :: array <int,N >>`应该足够了. (2认同)

Tim*_*mmm 25

您可以使用的更容易的替代方案是shared_ptr<vector<int>>.

  • 另一个区别是它比原始阵列稍微大一点*.一般不是真正的问题,但我们不要假装1 == 1.1. (8认同)
  • 是的.或者向量是数组的超集 - 它具有相同的内存中表示(加上元数据),但可以调整大小.实际上并不存在任何需要数组但不能使用向量的情况. (5认同)
  • 然后你可以使用`shared_ptr <array <int,6 >>`. (3认同)
  • 这里的区别在于向量大小不再是静态的,并且对数据的访问将通过双重间接完成.如果性能不是关键问题,则可行,否则共享阵列可能有其自身的原因. (2认同)
  • 在某些情况下,数组中的数据源意味着转换为向量是不必要的或不必要的; 例如从相机获取帧时 (或者,这是我的理解,无论如何) (2认同)