Подтвердить что ты не робот

Можете ли вы использовать shared_ptr для RAII массивов в стиле C?

Я работаю над секцией кода, которая имеет много возможных точек отказа, из-за которых она рано выходит из функции. Библиотеки, с которыми я взаимодействую, требуют, чтобы массивы C-стиля были переданы в функции. Поэтому вместо вызова delete на массивах в каждой точке выхода я делаю это:

void SomeFunction(int arrayLength)
{
   shared_ptr<char> raiiArray(new char[arrayLength]);
   pArray = raiiArray.get();

   if(SomeFunctionThatRequiresCArray(pArray) == FAILED) { return; }

   //etc.
}

Я хотел использовать unique_ptr, но мой текущий компилятор не поддерживает его, и в этом случае накладные расходы ссылочного значения не имеют большого значения.

Мне просто интересно, есть ли у кого-нибудь мысли об этой практике при взаимодействии с устаревшим кодом.

ОБНОВЛЕНИЕ Я полностью забыл о вызове shared_ptr delete вместо delete []. Я просто не видел утечек памяти и решил пойти с ним. Даже не думал использовать вектор. Поскольку я в последнее время вникал в новый (для меня) С++, я думаю, что у меня есть случай "Если у вас единственный инструмент, это молот, все выглядит как гвоздь". синдром. Спасибо за отзывы.

UPDATE2 Я решил, что изменил бы вопрос и предоставил бы ответ, чтобы сделать его немного более ценным для тех, кто совершил ту же ошибку, что и я. Хотя есть альтернативы типа scoped_array, shared_array и vector, вы можете использовать shared_ptr для управления областью массива (но после этого я понятия не имею, почему я хочу):

template <typename T>
    class ArrayDeleter
    {
    public:
        void operator () (T* d) const
        {
            delete [] d;
        }
    };

void SomeFunction(int arrayLength)
    {
       shared_ptr<char> raiiArray(new char[arrayLength], ArrayDeleter<char>());
       pArray = raiiArray.get();

       if(SomeFunctionThatRequiresCArray(pArray) == FAILED) { return; }

       //etc.
    }
4b9b3361

Ответ 1

Не используйте shared_ptr или scoped_ptr для хранения указателей на динамически распределенные массивы. shared_ptr и scoped_ptr использовать delete ptr; для очистки, когда указатель больше не ссылается/выходит за пределы области видимости, которая вызывает поведение undefined в динамически распределенном массиве. Вместо этого используйте shared_array или scoped_array, которые правильно используют delete[] ptr; при разрушении.

Чтобы ответить на ваш вопрос, если вы не собираетесь использовать интеллектуальный указатель, используйте scoped_array, так как он имеет меньше накладных расходов, чем shared_array.

В качестве альтернативы используйте std::vector в качестве хранилища массивов (векторы имеют гарантированное смежное распределение памяти).

Ответ 2

Используйте boost::scoped_array или даже лучше std::vector, если вы имеете дело с массивом.

Ответ 3

Я очень рекомендую просто использовать std::vector. Элементы в vectors выделяются в куче и будут удалены, когда vector выходит за пределы области видимости, где бы вы ни покидали функцию.

Чтобы передать vector в устаревший код, требующий массивы стиля C, просто пройдите &vectorName[0]. Элементы гарантированно смежны в памяти.

Ответ 4

Некоторые замечания для пользователей С++ 11:

Для shared_ptr в С++ 11 используется деблокировка по умолчанию для типов массивов, определенных в <memory>, и стандартная совместимость (по окончательной черновике), поэтому для таких случаев они могут использоваться без дополнительных причудливых удалений:

std::shared_ptr<char> raiiArray(new char[arrayLength], std::default_delete<char[]>()); 

unique_ptr в С++ 11 имеет частичную специализацию для работы с new[] и delete[]. К сожалению, у него нет общего поведения. Должна быть хорошей причиной, по которой нет такой специализации для shared_ptr, но я не искал ее, если вы ее знаете, пожалуйста, поделитесь ею.

Ответ 6

Это

shared_ptr<char*> raiiArray(new char[arrayLength]);

не является хорошей практикой, но вызывает поведение undefined, поскольку вы выделяете оператор new[], но shared_ptr использует operator delete для освобождения памяти. Правильная вещь - boost::shared_array или добавить пользовательский отладчик.