С 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[]>());
лямбда-выражение
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его, чтобы он мог работать «из коробки» для случаев, когда он владеет массивом объектов. Текущий проект shared_ptrизменений, намеченных для этого TS, может быть найден в N4082 . Эти изменения будут доступны через std::experimentalпространство имен и включены в <experimental/memory>заголовок. Вот некоторые из важных изменений в поддержке shared_ptrмассивов:
- Определение element_typeизменения типа члена
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[]>и 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*.
std::vector. Вы должны быть осторожны, чтобы передать массив, используя ссылки, чтобы вы не делали его копии. Синтаксис для доступа к данным чище, чем shared_ptr, и изменить его размер очень легко. И вы получите все добро STL, если захотите.