2

我正在学习 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没有链接?

谢谢。

4

1 回答 1

2

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

如果您将一本书印刷两次,您是否希望它神奇地与几个月前印刷的另一本书在同一个图书馆中结束?

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

如果您的副本也将“神奇地”克隆钩子,那将破坏容器不变量,或提出问题 /where/ 应将副本插入容器中。

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

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 too。

于 2014-12-11T11:36:13.323 回答