只是一个关于shared_ptr的小查询。
使用shared_ptr指向数组是一个好习惯吗?例如,
shared_ptr<int> sp(new int[10]);
如果不能,为什么不能?我已经意识到的一个原因是不能增加/减少shared_ptr。因此,它不能像普通的数组指针那样使用。
只是一个关于shared_ptr的小查询。
使用shared_ptr指向数组是一个好习惯吗?例如,
shared_ptr<int> sp(new int[10]);
如果不能,为什么不能?我已经意识到的一个原因是不能增加/减少shared_ptr。因此,它不能像普通的数组指针那样使用。
在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); Requires: Y shall be a complete type. The expression delete[] p, when T is an array type, or delete p, when T is not an array type, shall have well-defined behavior, and shall not throw exceptions. ... Remarks: When T is an array type, this constructor shall not participate in overload resolution unless the expression delete[] p is well-formed and either T is U[N] and Y(*)[N] is convertible to T*, or T is U[] and Y(*)[] is convertible to T*. ...
为了支持这一点,成员类型element_type现在定义为
using element_type = remove_extent_t<T>;
可以使用操作符[]访问数组元素
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++库基础扩展引入的变化
Another pre-C++17 alternative to the ones listed above was provided by the Library Fundamentals Technical Specification, which augmented shared_ptr to allow it to work out of the box for the cases when it owns an array of objects. The current draft of the shared_ptr changes slated for this TS can be found in N4082. These changes will be accessible via the std::experimental namespace, and included in the <experimental/memory> header. A few of the relevant changes to support shared_ptr for arrays are:
—成员类型element_type的定义发生了变化
typedef T element_type; typedef typename remove_extent<T>::type element_type;
—正在添加成员操作符[]
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*。