当使用侵入式容器时,最繁琐的任务之一是对已擦除元素的管理。当使用 STL 容器时,容器本身会解除链接并销毁包含的元素,但是对于侵入式容器,用户必须在从容器中擦除元素后显式销毁该对象。这使得类似 STL 的函数擦除多个对象变得无用:用户无法销毁每个擦除的元素。例如,我们来看一下 remove_if
函数,它来自 list
template<class Pred> void remove_if(Pred pred);
用户如何销毁将根据谓词擦除的元素(例如,使用 operator delete
)?Boost.Intrusive 容器提供了额外的函数,这些函数接受一个函数对象,该对象将在元素从容器中擦除后被调用。例如,list
提供了
template<class Pred, class Disposer> void remove_and_dispose_if(Pred pred, Disposer disposer)
使用此函数,如果 disposer 函数销毁一个对象,用户可以有效地移除和销毁元素:remove_and_dispose_if
将为每个移除的元素调用 “disposer” 函数对象。list
提供了更多将 disposer 函数对象作为参数的函数,例如 erase_and_dispose
、clear_and_dispose
、remove_and_dispose
等。
请注意,disposer 函数不一定只销毁对象。它可以实现任何其他操作,例如将移除的对象插入到另一个容器中。让我们看一个小例子
#include <boost/intrusive/list.hpp> using namespace boost::intrusive; //A class that can be inserted in an intrusive list class my_class : public list_base_hook<> { public: my_class(int i) : int_(i) {} int int_; //... }; //Definition of the intrusive list typedef list<my_class> my_class_list; //The predicate function struct is_even { bool operator()(const my_class &c) const { return 0 == (c.int_ % 2); } }; //The disposer object function struct delete_disposer { void operator()(my_class *delete_this) { delete delete_this; } }; int main() { const int MaxElem = 100; //Fill all the nodes and insert them in the list my_class_list list; try{ //Insert new objects in the container for(int i = 0; i < MaxElem; ++i) list.push_back(*new my_class(i)); //Now use remove_and_dispose_if to erase and delete the objects list.remove_and_dispose_if(is_even(), delete_disposer()); } catch(...){ //If something throws, make sure that all the memory is freed list.clear_and_dispose(delete_disposer()); throw; } //Dispose remaining elements list.erase_and_dispose(list.begin(), list.end(), delete_disposer()); return 0; }
所有 Boost.Intrusive 容器都为所有从容器中擦除元素的函数提供了这些 “擦除 + 处置” 附加成员。