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

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

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 * вы пытаетесь добавить никогда не будет утечка, даже если исключение.

1

Другие решения