Как безопасно заполнить контейнеры указателей Boosts?

Первый пример Boost Pointer Container добавляет необработанный указатель на структуру:

class zoo
{
    boost::ptr_vector<animal> the_animals;
public:

    void add_animal( animal* a )
    {
        the_animals.push_back( a );
    }
};

Но что, если push_backили любая другая функция-член, которая может инициировать перераспределение, выдает исключение во время процесса? Насколько я понимаю, в этом случае вызывающая сторона должна управлять памятью для данного объекта, но поскольку вызывающая сторона передает необработанный указатель на класс, целью которого является управление памятью, наиболее вероятно, что вызывающая сторона не ' т.

Итак, не нужно ли использовать какой-то уникальный умный указатель в приведенном выше примере кода, чтобы обернуть указатель перед его передачей в контейнер и быть абсолютно уверенным в отсутствии утечек памяти? Контейнеры обеспечивают перегрузку для таких интеллектуальных указателей, но они не навязывают их использование.

Или аргумент, что контейнеры просто никогда не будут генерировать исключения во время какой-либо операции добавления, и это всегда успешно?

1 ответ

Решение

Проблемы, которые у вас есть, очень актуальны, если вы используете std::vector<animal*> вместо boost::ptr_vector<animal>, Boost.PointerContainer предназначен для обработки указателей на ресурсы, которые необходимо освободить, поэтому он избавляет вас от необходимости беспокоиться о таких вещах.

Документация Boost предоставляет гарантии безопасности исключений для различных функций-членов. ptr_vector наследуется push_back от ptr_sequence_adaptor и это перечисляет поведение push_back как

void push_back( T* x );

Требования: x != 0
Эффекты: вставляет указатель в контейнер и становится его владельцем.
Броски: bad_pointer если x == 0
Исключительная безопасность: Сильная гарантия

Сильная гарантия означает, что если push_back бросает, состояние контейнера откатывается до того, что было непосредственно перед вызовом push_back и ни один ресурс не просочился. Теперь вы можете утверждать, что это не гарантирует ничего о ресурсе, который вы пытаетесь добавить в контейнер, но со стороны реализации было бы очень плохо допустить утечку этого ресурса, особенно после вызова push_back должен стать владельцем объекта, передаваемого вызывающим абонентом.

Если мы посмотрим на реализацию push_back, это показывает, как ptr_vector гарантирует, что ресурс, который вы пытаетесь добавить, не пропущен.

void push_back(value_type x)  // strong               
{
    this->enforce_null_policy(x, "Null pointer in 'push_back()'");

    auto_type ptr(x);           // notrow
    this->base().push_back(x);  // strong, commit
    ptr.release();                // nothrow
}

Так что auto_type сначала строится до фактического push_back операция предпринимается. Немного больше копаться показывает, что auto_type это псевдоним для static_move_ptr, который является интеллектуальным типом указателя, который при необходимости освобождает принадлежащий ему ресурс при уничтожении.

Таким образом, в показанном примере animal * вы пытаетесь добавить никогда не будет утечка, даже если исключение.

Другие вопросы по тегам