C++ shared_ptr 到数组:应该使用它吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13061979/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:55:26  来源:igfitidea点击:

shared_ptr to an array : should it be used?

c++c++11shared-ptr

提问by tshah06

Just a small query regarding shared_ptr.

只是一个关于shared_ptr.

Is it a good practice to use shared_ptrpointing to an array? For example,

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

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

If not, then why not? One reason I am already aware of is one can not increment/decrement the shared_ptr. Hence it can not be used like a normal pointer to an array.

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

回答by Praetorian

With C++17, shared_ptrcan be used to manage a dynamically allocated array. The shared_ptrtemplate argument in this case must be T[N]or T[]. So you may write

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

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

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

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

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

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

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

要求:Y应该是一个完整的类型。表达式delete[] p,whenT是数组类型,或者delete p,whenT不是数组类型,应具有明确定义的行为,并且不应引发异常。
...
备注:T是一个数组类型,则此构造不得参加重载除非表达delete[] p是公形成,要么TU[N]Y(*)[N]可转化为T*或者TU[]Y(*)[]可转化成T*。...

To support this, the member type element_typeis now defined as

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

using element_type = remove_extent_t<T>;

Array elements can be access using operator[]

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

  element_type& operator[](ptrdiff_t i) const;

Requires:get() != 0 && i >= 0. If Tis U[N], i < N. ...
Remarks:When Tis not an array type, it is unspecified whether this member function is declared. If it is declared, it is unspecified what its return type is, except that the declaration (although not necessarily the definition) of the function shall be well formed.

  element_type& operator[](ptrdiff_t i) const;

要求:get() != 0 && i >= 0。如果TU[N]i < N。...
备注:T不是数组类型时,未指定是否声明该成员函数。如果已声明,则未指定其返回类型是什么,除非函数的声明(尽管不一定是定义)格式正确。



Prior to C++17, shared_ptrcould notbe used to manage dynamically allocated arrays. By default, shared_ptrwill call deleteon the managed object when no more references remain to it. However, when you allocate using new[]you need to call delete[], and not delete, to free the resource.

之前C ++ 17shared_ptr可以被用来管理动态分配数组。默认情况下,shared_ptrdelete在没有更多引用时调用托管对象。但是,当您分配 using 时,new[]您需要调用delete[]而非delete来释放资源。

In order to correctly use shared_ptrwith an array, you must supply a custom deleter.

为了正确使用shared_ptr数组,您必须提供自定义删除器。

template< typename T >
struct array_deleter
{
  void operator ()( T const * p)
  { 
    delete[] p; 
  }
};

Create the shared_ptr as follows:

创建 shared_ptr 如下:

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

Now shared_ptrwill correctly call delete[]when destroying the managed object.

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

The custom deleter above may be replaced by

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

  • the std::default_deletepartial specialization for array types

    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; });
    
  • 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; });
    

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

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

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


Changes introduced by the C++ Extensions for Library Fundamentals

库基础的 C++ 扩展引入的更改

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

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

— The definition of the member type element_typechanges

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

typedef T element_type;

 typedef typename remove_extent<T>::type element_type;

typedef T element_type;

 typedef typename remove_extent<T>::type element_type;

— Member operator[]is being added

operator[]正在添加成员

 element_type& operator[](ptrdiff_t i) const noexcept;
 element_type& operator[](ptrdiff_t i) const noexcept;

— Unlike the unique_ptrpartial specialization for arrays, both shared_ptr<T[]>and shared_ptr<T[N]>will be valid and both will result in delete[]being called on the managed array of objects.

— 与unique_ptr数组的部分特化不同,shared_ptr<T[]>shared_ptr<T[N]>都是有效的,并且都将导致在delete[]对象的托管数组上被调用。

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

Requires: Yshall be a complete type. The expression delete[] p, when Tis an array type, or delete p, when Tis not an array type, shall be well-formed, shall have well defined behavior, and shall not throw exceptions. When Tis U[N], Y(*)[N]shall be convertible to T*; when Tis U[], Y(*)[]shall be convertible to T*; otherwise, Y*shall be convertible to T*.

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

要求Y应该是一个完整的类型。表达式delete[] p, whenT是数组类型,或delete p, whenT不是数组类型,应格式良好,应具有明确定义的行为,并且不应引发异常。当T是 时U[N]Y(*)[N]应可转换为T*; 当T是 时U[]Y(*)[]应可转换为T*;否则,Y*应转换为T*

回答by Timmmm

A possibly easier alternative that you might be able to use is shared_ptr<vector<int>>.

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