С 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, если захотите.