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

问题描述 投票:0回答:2

你可以让

std::shared_ptr
指向一个数组吗?例如,

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

如果没有,那为什么不呢?我已经知道的原因之一是无法增加/减少

std::shared_ptr
。因此它不能像普通的数组指针一样使用。

c++ c++11 shared-ptr smart-pointers
2个回答
320
投票

使用 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
(当
T
是数组类型时)或
delete p
(当
T
不是数组类型时)应具有明确定义的行为,并且不应引发异常。
...
备注:
T
为数组类型时,此构造函数不应参与重载决策,除非表达式
delete[] p
格式良好且
T
U[N]
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
。如果
T
U[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[]>());
    
    
  • 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 之前列出的替代方案是由

库基础技术规范 提供的,它增强了 shared_ptr

,使其能够在拥有对象数组的情况下开箱即用。该 TS 的 
shared_ptr
 更改的当前草案可以在 
N4082 中找到。这些更改可以通过 std::experimental
 命名空间访问,并包含在 
<experimental/memory>
 标头中。支持数组 
shared_ptr
 的一些相关更改包括:

— 成员类型的定义

element_type

发生变化

typedef T 元素类型;

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

要求Y

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


32
投票
您可能可以使用的一个可能更简单的替代方案是

shared_ptr<vector<int>>

© www.soinside.com 2019 - 2024. All rights reserved.