关于shared_ptr
的一个小问题。
使用指向数组的shared_ptr
是一个好习惯吗?例如,
shared_ptr<int> sp(new int[10]);
如果没有,那么为什么不呢?我已经意识到的一个原因是无法递增/递减shared_ptr
。因此它不能像普通指针一样使用。
答案 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
是数组类型时,表达式T
或delete p
当T
不是数组类型时,应具有明确定义的行为,并且不应抛出异常。
...
备注:当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
。如果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;
}
};
数组,您必须提供自定义删除工具。
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
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 p
或T
当T
不是数组类型时,应该是格式良好的,应该有明确定义的行为,并且不得抛出异常。当U[N]
为Y(*)[N]
时,T*
应可转换为T
;当U[]
为Y(*)[]
时,T*
可转换为Y*
;否则,T*
应可转换为{{1}}。
答案 1 :(得分:25)
您可以使用的更简单的替代方法是shared_ptr<vector<int>>
。