Re: [Boost-bugs] [Boost C++ Libraries] #11801: Recursive modify in multi_index sometimes does not update index correctly

Subject: Re: [Boost-bugs] [Boost C++ Libraries] #11801: Recursive modify in multi_index sometimes does not update index correctly
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2015-11-19 16:00:03


#11801: Recursive modify in multi_index sometimes does not update index correctly
-------------------------------------+-------------------------------------
  Reporter: Valentyn Shtronda | Owner: joaquin
  <valiko.ua@…> | Status: closed
      Type: Bugs | Component: multi_index
 Milestone: To Be Determined | Severity: Problem
   Version: Boost 1.59.0 | Keywords: multi_index
Resolution: invalid | multi_index_container recursive
                                     | modify
-------------------------------------+-------------------------------------

Comment (by joaquin):

 ''In my lambda I modify layer member and do not change name member.
 Doesn't this mean that first index remains sorted, is not broken, and I
 can use find on it even inside lambda recursively?''

 Unfortunately not: when `modify` reindexes, it does so on ''every'' index;
 so, if you broke the element pointed to by `it` and then, further down the
 code, you do a `modify(dep_it,...)` (within the recursive call to
 `calc_layer`), Boost.!MultiIndex does not know that `*it` is misplaced and
 havoc ensues.

 ''I need to keep circular dependency check because user-supplied data can
 contain them...''

 OK, there's another way to do this that lets you keep your
 `CALCULATION_IN_PROGRESS` feature:

 {{{
 bool succeeded = deps_map.modify(it,
     [=](node_info_t& node_info)
     {
         if (node_info.deps.size() == 0)
         {
             node_info.layer = 0;
         }
         else
         {
             index_by_name_t& index_by_name = deps_map.get<by_name>();
             node_info.layer = CALCULATION_IN_PROGRESS;
             index_by_name.modify(it,[](node_info_t&){});
             for (const std::string& dep_name : node_info.deps)
             {
                 index_by_name_t::iterator dep_it =
 index_by_name.find(dep_name);
                 if (dep_it == deps_map.end())
                 {
                     node_info.layer = UNINITIALIZED;
                     printf("Unknown dependency.\n");
                     return;
                 }
                 if (!calc_layer(dep_it))
                 {
                     node_info.layer = UNINITIALIZED;
                     return;
                 }
                 node_info.layer = std::max(node_info.layer, dep_it->layer
 + 1);
                 index_by_name.modify(it,[](node_info_t&){});
             }
         }
     });
 }}}

 What we're doing here is to reindex immediately after any element
 modification, without waiting for the lib to do it on function exit.


 {{{
 node_info.layer = CALCULATION_IN_PROGRESS;
 index_by_name.modify(it,[](node_info_t&){});
 ...
 node_info.layer = std::max(node_info.layer, dep_it->layer + 1);
 index_by_name.modify(it,[](node_info_t&){});
 }}}

 This is done by calling `modify` with a do-nothing function after we
 change the value pointed to by `it` (i.e. `node_info`). I've checked and
 it works, please confirm back.

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/11801#comment:4>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:19 UTC