Одной из самых утомительных задач при использовании интрузивных контейнеров является управление стертыми элементами. При использовании STL-контейнеров сам контейнер отсоединяется и разрушает содержащиеся в нем элементы, но с помощью инвазивных контейнеров пользователь должен явно уничтожить объект после стирания элемента из контейнера. Это делает STL-подобные функции, стирающие несколько объектов, бесполезными: пользователь не может уничтожить каждый стертый элемент. Например, возьмем функцию<remove_if
>из<list
>:
template<class Pred>
void remove_if(Pred pred);
Как пользователь может уничтожить элементы (скажем, используя<operator
delete
>), которые будут стерты в соответствии с предикатом?НавязчивыйКонтейнеры предлагают дополнительные функции, которые принимают функциональный объект, который будет называться после того, как элемент был стерт из контейнера. Например,<list
>предлагает:
template<class Pred, class Disposer>
void remove_and_dispose_if(Pred pred, Disposer disposer)
С помощью этой функции пользователь может эффективно удалять и уничтожать элементы, если функция утилизатора разрушает объект:<remove_and_dispose_if
>будет называть объект функции «утилизатора» для каждого удаленного элемента.<list
>предлагает больше функций, принимая объект функции дисперсии в качестве аргумента, например<erase_and_dispose
>,<clear_and_dispose
>,<remove_and_dispose
>и т. д.
Обратите внимание, что диспозиционная функция не должна просто разрушать объект. Он может выполнять любые другие операции, такие как вставка удаленного объекта в другой контейнер. Рассмотрим небольшой пример:
#include <boost/intrusive/list.hpp>
using namespace boost::intrusive;
class my_class : public list_base_hook<>
{
public:
my_class(int i)
: int_(i)
{}
int int_;
};
typedef list<my_class> my_class_list;
struct is_even
{
bool operator()(const my_class &c) const
{ return 0 == (c.int_ % 2); }
};
struct delete_disposer
{
void operator()(my_class *delete_this)
{ delete delete_this; }
};
int main()
{
const int MaxElem = 100;
my_class_list list;
try{
for(int i = 0; i < MaxElem; ++i) list.push_back(*new my_class(i));
list.remove_and_dispose_if(is_even(), delete_disposer());
}
catch(...){
list.clear_and_dispose(delete_disposer());
throw;
}
list.erase_and_dispose(list.begin(), list.end(), delete_disposer());
return 0;
}
Все контейнерыBoost.Intrusiveпредлагают эти дополнительные элементы для всех функций, которые стирают элемент из контейнера.