Search code examples
boostboost-multi-index

How do I replace an item in a multi index container without affecting the insertion order?


I have a multi index container with four indexes. One of the indexes is a random access index, used to maintain the insertion order. When a property on an element of the container is updated externally, I would like the relevant index to be updated. However, I would like to preserve the order of insertion.

I would like to know whether the order of insertion will be affected if I replace the value in question. If not, how can I achieve this?


Solution

  • I would expect modify() to work here. Let me try it out and show an example:

    #include <boost/multi_index_container.hpp>
    #include <boost/multi_index/random_access_index.hpp>
    #include <boost/multi_index/member.hpp>
    #include <boost/multi_index/ordered_index.hpp>
    #include <iostream>
    
    struct Data
    {
        int i;
        std::string index1;
    
        friend std::ostream& operator<<(std::ostream& os, Data const& v) {
            return os << "{ " << v.i << ", '" << v.index1 << "' }";
        }
    
    };
    
    namespace bmi = boost::multi_index;
    
    using Table = bmi::multi_index_container<
        Data,
        bmi::indexed_by<
            bmi::random_access<>,
            bmi::ordered_unique<bmi::member<Data, std::string, &Data::index1> >
        > >;
    
    static std::ostream& operator<<(std::ostream& os, Table const& table) {
        os << "insertion order: "; for(auto const& element : table) os << element << "; ";
        os << "\nsecondary index: ";for(auto const& element : table.get<1>()) os << element << "; ";
        return os << "\n";
    }
    
    int main()
    {
        Table table {
            { 42, "aap" },
            { 43, "noot" },
            { 44, "mies" } 
        };
    
        std::cout << "Before:\n" << table << "\n";
    
        table.modify(table.begin(),  [](Data& v) { v.i *= v.i; });
        std::cout << "Edit 1:\n" << table << "\n";
    
        table.modify(table.begin()+2, [](Data& v) { v.index1 = "touched"; });
        std::cout << "Edit 2:\n" << table << "\n";
    }
    

    Prints

    Before:
    insertion order: { 42, 'aap' }; { 43, 'noot' }; { 44, 'mies' }; 
    secondary index: { 42, 'aap' }; { 44, 'mies' }; { 43, 'noot' }; 
    
    Edit 1:
    insertion order: { 1764, 'aap' }; { 43, 'noot' }; { 44, 'mies' }; 
    secondary index: { 1764, 'aap' }; { 44, 'mies' }; { 43, 'noot' }; 
    
    Edit 2:
    insertion order: { 1764, 'aap' }; { 43, 'noot' }; { 44, 'touched' }; 
    secondary index: { 1764, 'aap' }; { 43, 'noot' }; { 44, 'touched' }; 
    

    Which is likely what you wanted?

    See it Live On Coliru