Можете ли вы использовать shared_ptr для RAII массивов в стиле C? - PullRequest
26 голосов
/ 16 июля 2010

Я работаю над частью кода, в которой есть много возможных точек сбоя, из-за которых он рано выходит из функции. Библиотеки, с которыми я взаимодействую, требуют, чтобы массивы в стиле 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 []. Я просто не увидел утечек памяти и решил пойти с этим. Даже не думал использовать вектор. Так как я в последнее время углубляюсь в новый (для меня) C ++, я думаю, что у меня есть случай «Если единственный инструмент, который у вас есть, это молоток, все выглядит как гвоздь». синдром. Спасибо за отзыв.

ОБНОВЛЕНИЕ2 Я решил изменить вопрос и дать ответ, чтобы он стал немного более ценным для того, кто совершил ту же ошибку, что и я. Хотя есть альтернативы, такие как 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.
    }

Ответы [ 6 ]

27 голосов
/ 16 июля 2010

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

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

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

15 голосов
/ 16 июля 2010

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

7 голосов
/ 16 июля 2010

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

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

6 голосов
/ 17 августа 2013

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

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

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

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

5 голосов
/ 16 июля 2010

Для этого есть boost::scoped_ptr.

3 голосов
/ 16 июля 2010

Это

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

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

...