Я изучаю 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
не связан?
Спасибо вам.
Почему вы ожидаете, что скопированный узел будет в коллекции?
Если вы напечатаете книгу дважды, ожидаете ли вы, что она волшебным образом окажется в той же библиотеке, что и другая книга, напечатанная несколько месяцев назад?
Это просто другой объект. Также известен как копия.
Если ваша копия «магически» также клонирует хук, это либо нарушит инварианты контейнера, либо поставит вопрос / где / копия должна быть вставлена в контейнер.
После некоторых серьезных дискуссий я понял, что ты может быть хочу знать, как клонировать список наряду со значениями в векторе:
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());
}
Фактически, вот версия, которая помещает клонированные узлы прямо в тот же вектор, что и исходные узлы, для удовольствия: Жить на Колиру тоже.