c++rvaluelvalueintrusive-containersboost-intrusive

Why boost intrusive list 's push_back function requires lvalue?


I am learning intrusive list:

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

I understand the basic idea of intrusive list, but I cannot understand why push_back requires lvalue specifically. From a logic perspective, why intrusive list cannot cope with rvalue ?

Does lvalue requirement imply that, the user need to handle the life-circle of DummyObject by himself? In other word, when IntrusiveList pop_front, the pop-ed object will not be destructed ?

Also, event I pass by 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;
}

the binary failed one of the assert:

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>]: Assertion `!hook.is_linked()' failed.


Solution

  • This is simple intrusive container doesn't perform memory management. It is your responsibility to ensure that stored object outlives intrusive container.

    This is point out in documentation:

    Intrusive and non-intrusive containers - 1.64.0

    • The user has to manage the lifetime of inserted objects independently from the containers.

    Now temporary object will live shorter then intrusive container leading to undefined behavior, intrusive container do not create any copy. so use of r-value is not desired.

    Now this version of your example works fine (no crash):

    int main()
    {
      DummyObject a(22.2);
      IntrusiveListContainer  intrusivecontainer;
      NonintrusiveListContainer  nonintrusivecontainer;
    
      intrusivecontainer.push_back(a); // ERROR
      nonintrusivecontainer.push_back(a);// compiled
    
      return 0;
    }
    

    And on other hand this version ends with assertion failure:

    int main()
    {
      IntrusiveListContainer  intrusivecontainer;
      NonintrusiveListContainer  nonintrusivecontainer;
      DummyObject a(22.2);
    
      intrusivecontainer.push_back(a); // ERROR
      nonintrusivecontainer.push_back(a);// compiled
    
      return 0;
    }