Cloning Boost.Intrusive containers

| Home | Libraries | People | FAQ | More

## Cloning Boost.Intrusive containers

As previously mentioned, Boost.Intrusive containers are non-copyable and non-assignable, because intrusive containers don't allocate memory at all. To implement a copy-constructor or assignment operator, the user must clone one by one all the elements of the container and insert them in another intrusive container. However, cloning by hand is usually more inefficient than a member cloning function and an specialized cloning function can offer more guarantees than the manual cloning (better exception safety guarantees, for example).

To ease the implementation of copy constructors and assignment operators of classes containing Boost.Intrusive containers, all Boost.Intrusive containers offer an special cloning function called `clone_from`.

Apart from the container to be cloned, `clone_from` takes two function objects as arguments. For example, the `clone_from` member function of `list`:

    template <class Cloner, class Disposer>
    void clone_from(const list &src, Cloner cloner, Disposer disposer);

This function will make `*this` a clone of `src`. Let's explain the arguments:

- The first parameter is the list to be cloned.
- The second parameter is a function object that will clone `value_type` objects and return a pointer to the clone. It must implement the following function: `pointer operator()(const value_type &)`.
- The second parameter is a function object that will dispose `value_type` objects. It's used first to empty the container before cloning and to dispose the elements if an exception is thrown.

The cloning function works as follows:

- First clears and disposes all the elements from *this using the disposer function object.
- After that starts cloning all the elements of the source container using the cloner function object.
- If any operation in the cloning function (for example, the cloner function object) throws, all the constructed elements are disposed using the disposer function object.

Here's an example of `clone_from`:

    #include <boost/intrusive/list.hpp>
    #include <iostream>
    #include <vector>

    using namespace boost::intrusive;

    //A class that can be inserted in an intrusive list
    class my_class : public list_base_hook<>
    {
       public:
       friend bool operator==(const my_class &a, const my_class &b)
       {  return a.int_ == b.int_;   }

       int int_;

       //...
    };

    //Definition of the intrusive list
    typedef list<my_class> my_class_list;

    //Cloner object function
    struct new_cloner
    {
       my_class *operator()(const my_class &clone_this)
       {  return new my_class(clone_this);  }
    };

    //The disposer object function
    struct delete_disposer
    {
       void operator()(my_class *delete_this)
       {  delete delete_this;  }
    };

    int main()
    {
       const int MaxElem = 100;
       std::vector<my_class> nodes(MaxElem);

       //Fill all the nodes and insert them in the list
       my_class_list list;

       for(int i = 0; i < MaxElem; ++i) nodes[i].int_ = i;

       list.insert(list.end(), nodes.begin(), nodes.end());

       //Now clone "list" using "new" and "delete" object functions
       my_class_list cloned_list;
       cloned_list.clone_from(list, new_cloner(), delete_disposer());

       //Test that both are equal
       if(cloned_list != list)
          std::cout << "Both lists are different" << std::endl;
       else
          std::cout << "Both lists are equal" << std::endl;

       //Don't forget to free the memory from the second list
       cloned_list.clear_and_dispose(delete_disposer());
       return 0;
    }