shared_ptr и массивы



Есть одна не самая приятная вещь при работе с std::shared_ptr. С момента его выхода в С++11 и в С++14 он не может быть использован из коробки для того, чтобы хранить динамические массивы. По дефолту во всех случаях при исчерпании ссылок на объект, шареный указатель вызывает оператор delete. Однако, когда мы аллоцируем динамический массив new[], мы хотим вызвать delete[] для его удаления. Но shared_ptr просто вызовет delete. А это неопределенное поведение.



То есть я не могу просто так вот взять и написать



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




Кстати говоря, у его собрата std::unique_ptr с этим все получше. У него есть отдельная частичная специализация для массивов. Поэтому вот так я могу написать спокойно:



std::unique_ptr<int[]> up(new int[10]); // вызовется корректный delete[]




Что можно сделать, чтобы таки использовать сишные массивы с шареным указателем?



👉🏿 Обернуть указатель на массив в класс и шарить уже объекты этого класса. Типа того(упрощенно):

template <class T>

struct DynamicArrayWrapper {

DynamicArrayWrapper(size_t size) : ptr{new T[size]} {}

~DynamicArrayWrapper() {delete[] ptr;}

T * ptr;

};



std::shared_ptr<DynamicArrayWrapper> sp{10};




У такого метода есть 2 проблемы. Первое - прокси класс. Дополнительные обертки увеличивают объем и сложность кода и затрудняют его понимание. Второе - перформанс. Здесь уже два уровня индирекции, что замедлит обработку.



👉🏿 Передать свой кастомный делитер. Тут тоже несколько вариантов.

⚡️Написать свой:

template< typename T >

struct array_deleter

{

void operator ()( T const * p)

{

delete[] p;

}

};



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




⚡️Использовать лямбду:

std::shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });




⚡️Ну или воспользоваться уже готовым вариантом:

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


std::default_delete имеет частичную специализацию для массивов.



Но! Какой хороший все-таки стандарт С++17, который поправил многие такие маленькие косячки. А как он это сделал - увидим в следующий раз)



Be comfortable to work with. Stay cool.



#cpp11 #memory