Почему функция push_back для навязчивого списка требует lvalue?
Учу навязчивый список:
#include <iostream>
#include <list>
#include <boost/intrusive/list.hpp>
struct DummyObject : public boost::intrusive::list_base_hook<>{
double price;
DummyObject(const double a): price(a){
}
};
using IntrusiveListContainer = boost::intrusive::list<DummyObject>;
using NonintrusiveListContainer = std::list<DummyObject>;
int main()
{
IntrusiveListContainer intrusivecontainer;
NonintrusiveListContainer nonintrusivecontainer;
intrusivecontainer.push_back(DummyObject (22.2)); // ERROR
nonintrusivecontainer.push_back(DummyObject (22.2));// compiled
return 0;
}
Я понимаю основную идею навязчивого списка, но не могу понять, почему push_back требует именно lvalue. С логической точки зрения, почему навязчивый список не может справиться с rvalue?
Означает ли требование lvalue, что пользователь должен самостоятельно управлять жизненным циклом DummyObject? Другими словами, когда IntrusiveList pop_front, всплывающий объект не будет разрушен?
Кроме того, событие, которое я передаю lvalue:
int main()
{
IntrusiveListContainer intrusivecontainer;
NonintrusiveListContainer nonintrusivecontainer;
DummyObject a(22.2);
intrusivecontainer.push_front(a); // compiled
//nonintrusivecontainer.push_back(DummyObject (22.2));// compiled
return 0;
}
двоичный файл не прошел одно из утверждений:
intrusivelist: /usr/include/boost/intrusive/detail/generic_hook.hpp:48: void boost:: intrusive:: detail:: destructor_impl (Hook&, boost:: intrusive:: detail:: link_dispatch<(boost:: intrusive:: link_mode_type)1>) [with Hook = boost:: intrusive:: generic_hook<(boost:: intrusive:: algo_types)0, boost:: intrusive:: list_node_traits, boost:: intrusive:: dft_tag, (boost:: intrusive:: link_mode_type)1, (boost:: intrusive:: base_hook_type)1>]: утверждение `!hook.is_linked()'не выполнено.
2 ответа
Этот простой навязчивый контейнер не выполняет управление памятью. Вы несете ответственность за то, чтобы сохраненный объект пережил навязчивый контейнер.
Это указано в документации:
Интрузивные и ненавязчивые контейнеры - 1.64.0
- Пользователь должен управлять временем жизни вставленных объектов независимо от контейнеров.
Теперь временный объект будет жить короче, чем навязчивый контейнер, что приведет к неопределенному поведению, навязчивый контейнер не создает никакой копии. поэтому использование r-значения нежелательно.
Теперь эта версия вашего примера работает нормально (без сбоев):
int main()
{
DummyObject a(22.2);
IntrusiveListContainer intrusivecontainer;
NonintrusiveListContainer nonintrusivecontainer;
intrusivecontainer.push_back(a); // ERROR
nonintrusivecontainer.push_back(a);// compiled
return 0;
}
С другой стороны, эта версия заканчивается ошибкой утверждения:
int main()
{
IntrusiveListContainer intrusivecontainer;
NonintrusiveListContainer nonintrusivecontainer;
DummyObject a(22.2);
intrusivecontainer.push_back(a); // ERROR
nonintrusivecontainer.push_back(a);// compiled
return 0;
}
У меня была такая же ошибка утверждения при работе с навязчивыми списками, даже при использовании lvalue. Ошибка утверждения произойдет, если список не будет пустым при уничтожении. Если вы выталкиваете () все значения до вызова деструктора списка, все должно быть в порядке.