Первый пример для Контейнер повышения указателя добавляет необработанный указатель на структуру:
class zoo
{
boost::ptr_vector<animal> the_animals;
public:
void add_animal( animal* a )
{
the_animals.push_back( a );
}
};
Но что, если push_back
или любая другая функция-член, которая может инициировать перераспределение, выдает исключение во время процесса? Насколько я понимаю, в этом случае вызывающий может управлять памятью для данного объекта, но поскольку вызывающий передает необработанный указатель на класс, целью которого является управление памятью, скорее всего вызывающий не ‘ т.
Итак, не нужно ли использовать какой-то уникальный умный указатель в приведенном выше примере кода, чтобы обернуть указатель перед его передачей в контейнер и быть абсолютно уверенным в отсутствии утечек памяти? Контейнеры обеспечивают перегрузку для таких умных указателей, но они не навязывают их использование.
Или аргумент, что контейнеры просто никогда не будут генерировать исключения во время какой-либо операции добавления, и это всегда успешно?
Ваши проблемы очень актуальны, если вы используете 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 *
вы пытаетесь добавить никогда не будет утечка, даже если исключение.