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

时间:2012-10-25 05:13:00

标签: c++ c++11 shared-ptr

关于shared_ptr的一个小问题。

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

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

如果没有,那么为什么不呢?我已经意识到的一个原因是无法递增/递减shared_ptr。因此它不能像普通指针一样使用。

2 个答案:

答案 0 :(得分:234)

使用 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);
     

要求: Y应为完整类型。当delete[] p是数组类型时,表达式Tdelete pT不是数组类型时,应具有明确定义的行为,并且不应抛出异常。
  ...
  备注:T是数组类型时,除非表达式delete[] p格式正确并且T为{{U[N],否则此构造函数不应参与重载决策1}}和Y(*)[N]可转换为T*,或T   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可以用于管理动态分配的数组。默认情况下,shared_ptr将在托管对象上再次调用delete时调用new[]。但是,当您使用delete[]分配时,需要调用delete而不是shared_ptr来释放资源。

为了正确使用template< typename T > struct array_deleter { void operator ()( T const * p) { delete[] p; } }; 数组,您必须提供自定义删除工具。

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

按如下方式创建shared_ptr:

shared_ptr

现在delete[]会在销毁托管对象时正确调用std::shared_ptr<int> sp(new int[10], std::default_delete<int[]>());

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

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

    std::shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });
    
  • 一个lambda表达式

    unique_ptr

此外,除非您确实需要共享托管对象的onwership,否则std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[] 更适合此任务,因为它具有数组类型的部分特化。

shared_ptr

C ++扩展库引入的更改

Library Fundamentals Technical Specification提供了上面列出的另一种前C ++ 17替代方案,它增加了shared_ptr以允许它在拥有数组的情况下开箱即用对象有关此TS的std::experimental更改的当前草案可在N4082中找到。这些更改可通过<experimental/memory>命名空间访问,并包含在shared_ptr标头中。支持element_type数组的一些相关更改是:

- 成员类型 typedef typename remove_extent<T>::type element_type; 的定义更改

  

typedef T 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);

Y
     

需要delete[] p应为完整类型。当T是数组类型时,表达式delete pTT不是数组类型时,应该是格式良好的,应该有明确定义的行为,并且不得抛出异常。当U[N]Y(*)[N]时,T*应可转换为T;当U[]Y(*)[]时,T*可转换为Y*;否则,T*应可转换为{{1}}。

答案 1 :(得分:25)

您可以使用的更简单的替代方法是shared_ptr<vector<int>>