如何使用Boost Intrusive克隆一个钩子?

时间:2014-12-10 11:45:26

标签: c++ boost intrusive-containers

我正在学习Boost Intrusive库。我尝试复制STL容器时遇到问题。我使用std :: vector。它包含模式list_base_hook中的类auto_unlink的元素,但是当您调用复制构造函数时,有关节点(is_linked())的信息将丢失。

我有以下代码:

 class helper_class
 {
     public:
         helper_class(void) { /* ... */ }
         helper_class(const helper_class& hc) { /* ... */ }
         helper_class(helper_class&& hc) { /* ... */ }
         helper_class & operator=(const helper_class& hc) { /* ... */ }
         helper_class & operator=(helper_class&& hc) { /* ... */ }
         virtual ~helper_class(void) { /* ... */ }
         // ...
 };

 typedef list_base_hook<link_mode<auto_unlink> > auto_hook;

 class my_class : public auto_hook
 {
     public:

         friend bool operator==(const my_class &a, const my_class &b)
         {
             return (a.int_ == b.int_) &&
                     (a.helper_class_ == b.helper_class_);
         }

         int int_;
         helper_class* helper_class_;

         // ...
 };

 typedef list<my_class, constant_time_size<false> >  my_class_list;

 struct new_cloner
 {
      my_class *operator()(const my_class &clone_this)
      {  return new my_class(clone_this);  }
 };

 struct delete_disposer
 {
      void operator()(my_class *delete_this)
      {  delete delete_this;  }
 };

 int main()
 {
     // ...
     helper_class the_helper_class;
     const int MaxElem = 100;
     std::vector<my_class> nodes(MaxElem);
     std::vector<my_class> copy_nodes(MaxElem);
     my_class_list list;

     for(int i = 0; i < MaxElem; ++i) {
         nodes[i].int_ = i;
         nodes[i].helper_class_ = &the_helper_class;
     }

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

     my_class_list cloned_list;
     cloned_list.clone_from(list, new_cloner(), delete_disposer());

     copy_nodes = nodes;

     std::cout  << "nodes[0].is_linked()       : "
                << ((nodes[0].is_linked()) ? "LINKED":"NO-LINKED")
                << std::endl;
     std::cout  << "copy_nodes[0].is_linked()  : "
                << ((copy_nodes[0].is_linked()) ? "LINKED":"NO-LINKED")
                << std::endl;
     std::cout  << "list[0].is_linked()        : "
                << (((*list.begin()).is_linked()) ? "LINKED":"NO-LINKED")
                << std::endl;
     std::cout  << "cloned_list[0].is_linked() : "
                << (((*cloned_list.begin()).is_linked()) ? "LINKED":"NO-LINKED")
                << std::endl;
     cloned_list.clear_and_dispose(delete_disposer());

     // ...

     return 0;
 };

标准输出:

nodes[0].is_linked()       : LINKED
copy_nodes[0].is_linked()  : NO-LINKED
list[0].is_linked()        : LINKED
cloned_list[0].is_linked() : LINKED

为什么向量copy_nodes没有链接?

谢谢你。

1 个答案:

答案 0 :(得分:2)

为什么您希望复制的节点位于集合中?

如果你打印一本书两次,你是否期望它与几个月前印刷的另一本书完全在同一个图书馆?

它只是一个不同的对象。也称为副本。

如果你的副本会神奇地&#34;克隆钩子也会破坏容器不变量,或者提出问题/应该在容器中插入副本的位置。

经过一番严肃的辩论后,我认为可能想知道如何克隆列表以及向量中的值

my_class_list cloned_list;
std::vector<my_class> cloned_nodes;
cloned_nodes.reserve(MaxElem);
cloned_list.clone_from(
        list, 
        [&cloned_nodes](my_class const&v) { cloned_nodes.push_back(v); return &cloned_nodes.back(); },
        [](my_class*){}
    );

这里没有删除(因为你无论如何都可以破坏矢量)。这是

的完整演示

<强> Live On Coliru

#include <boost/intrusive/list.hpp>
using namespace boost::intrusive;

struct my_class : list_base_hook<link_mode<auto_unlink> > { };
typedef list<my_class, constant_time_size<false> > my_class_list;

#include <iostream>

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

    //////////////////////////////////////////////
    // He's making a list
    my_class_list list;
    list.insert(list.end(), nodes.begin(), nodes.end());

    //////////////////////////////////////////////
    // He's checking it twice
    my_class_list cloned_list;
    std::vector<my_class> cloned_nodes;
    cloned_nodes.reserve(MaxElem);
    cloned_list.clone_from(
            list, 
            [&cloned_nodes](my_class const&v) { cloned_nodes.push_back(v); return &cloned_nodes.back(); },
            [](my_class*){}
        );

    std::cout << std::boolalpha;
    std::cout << "nodes[0].is_linked()       : " << nodes[0].is_linked()             << std::endl;
    std::cout << "cloned_nodes[0].is_linked(): " << cloned_nodes[0].is_linked()      << std::endl;
    std::cout << "list[0].is_linked()        : " << list.begin()->is_linked()        << std::endl;
    std::cout << "cloned_list[0].is_linked() : " << cloned_list.begin()->is_linked() << std::endl;

    //////////////////////////////////////////////
    // Gonna find out who's naughty or nice:
    auto nit = cloned_nodes.begin();
    auto lit = cloned_list.begin();

    while (nit != cloned_nodes.end() && lit != cloned_list.end()) {
        assert(&(*nit++) == &(*lit++)); // this would fail if you didn't `reserve()` the vector up front
    }

    //////////////////////////////////////////////
    // now, if you really want you can do
    cloned_list.clear();
    // after which the simplest thing to do would be `cloned_nodes.clear()`, but let's be very precise:
    cloned_nodes.erase(std::remove_if(
                cloned_nodes.begin(), cloned_nodes.end(), 
                [](my_class const& v) { return !v.is_linked(); }),
            cloned_nodes.end());
}

事实上,这是一个将克隆节点放在与源节点相同的向量中的版本,为了好玩: Live On Coliru