你能让 std::shared_ptr 管理用 new T[] 分配的数组吗?

2024-03-17

你能做一个std::shared_ptr http://en.cppreference.com/w/cpp/memory/shared_ptr指向一个数组?例如,

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

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


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

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

从n4659开始,[util.smartptr.shared.const] https://timsong-cpp.github.io/cppwp/n4659/util.smartptr.shared.const

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

要求: Y应该是一个完整的类型。表达方式delete[] p, when T是数组类型,或者delete p, when T不是数组类型,应具有明确定义的行为,并且不应引发异常。
...
Remarks: When T是数组类型,此构造函数不应参与重载决策,除非表达式delete[] p是格式良好的,并且T is U[N] and Y(*)[N]可转换为T*, or T is U[] and Y(*)[]可转换为T*. ...

为了支持这一点,成员类型element_type https://timsong-cpp.github.io/cppwp/n4659/util.smartptr.shared#1现在定义为

using element_type = remove_extent_t<T>;

可以使用以下方式访问数组元素operator[] https://timsong-cpp.github.io/cppwp/n4659/util.smartptr.shared.obs#8

  element_type& operator[](ptrdiff_t i) const;

要求: get() != 0 && i >= 0. If T is U[N], i < N. ...
Remarks: When T不是数组类型,未指定是否声明该成员函数。如果声明了它,则未指定其返回类型是什么,但函数的声明(尽管不一定是定义)应格式良好。


C++17 之前, shared_ptr could not用于管理动态分配的数组。默认情况下,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>());

Now shared_ptr将正确调用delete[]当销毁被管理对象时。

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

  • the std::default_delete http://en.cppreference.com/w/cpp/memory/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++ 库基础扩展引入的更改

上面列出的另一种 C++17 之前的替代方案由库基础技术规范 http://en.cppreference.com/w/cpp/experimental/lib_extensions,这增强了shared_ptr允许它在拥有对象数组的情况下开箱即用。目前的草案shared_ptr可以在以下位置找到此 TS 的更改N4082 http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n4082.pdf。这些更改可通过std::experimental命名空间,并包含在<experimental/memory>标头。支持的一些相关更改shared_ptr对于数组是:

— 成员类型的定义element_type changes

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[]> and shared_ptr<T[N]>将是有效的,并且两者都会导致delete[]在托管对象数组上调用。

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

你能让 std::shared_ptr 管理用 new T[] 分配的数组吗? 的相关文章

随机推荐