Почему функция 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. Ошибка утверждения произойдет, если список не будет пустым при уничтожении. Если вы выталкиваете () все значения до вызова деструктора списка, все должно быть в порядке.

Другие вопросы по тегам