Как клонировать крючок с помощью Boost Intrusive?

Я изучаю 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 не связан?

Спасибо вам.

2

Решение

Почему вы ожидаете, что скопированный узел будет в коллекции?

Если вы напечатаете книгу дважды, ожидаете ли вы, что она волшебным образом окажется в той же библиотеке, что и другая книга, напечатанная несколько месяцев назад?

Это просто другой объект. Также известен как копия.

Если ваша копия «магически» также клонирует хук, это либо нарушит инварианты контейнера, либо поставит вопрос / где / копия должна быть вставлена ​​в контейнер.

После некоторых серьезных дискуссий я понял, что ты может быть хочу знать, как клонировать список наряду со значениями в векторе:

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*){}
);

Здесь нет удаления (потому что вы можете просто уничтожить вектор). Вот полная демонстрация этого

Жить на Колиру

#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());
}

Фактически, вот версия, которая помещает клонированные узлы прямо в тот же вектор, что и исходные узлы, для удовольствия: Жить на Колиру тоже.

2

Другие решения


По вопросам рекламы [email protected]