Move element from boost multi_index array

后端 未结 2 694
天命终不由人
天命终不由人 2020-12-03 23:41

Let\'s say I have movable and not copyable object and I have boost multi-index array with random_access index. I need to move my object out of array front, but I cannot find

2条回答
  •  萌比男神i
    2020-12-04 00:38

    Non-const element operations are not supported because they could leave elements in a state which would break invariants placed on them by the various indexes.

    The closest thing you can do is using modify:

    moveonly pop_front(Table& table) {
        moveonly extracted;
    
        auto it = table.begin();
        if (it == table.end())
            throw std::logic_error("pop_front");
    
        if (table.modify(it, [&](moveonly& v) { extracted = std::move(v); })) {
            table.erase(it);
        }
    
        return extracted;
    }
    

    Note that modify does incur the cost of checking all indexes, and may fail. Fortunately, if it does fail, the effect is that iterator is erased:

    • Effects: Calls mod(e) where e is the element pointed to by position and rearranges *position into all the indices of the multi_index_container. Rearrangement on sequenced indices does not change the position of the element with respect to the index; rearrangement on other indices may or might not succeed. If the rearrangement fails, the element is erased.
    • Postconditions: Validity of position is preserved if the operation succeeds.

    And here's a live demo:

    Live On Coliru

    #include 
    #include 
    #include 
    
    struct moveonly {
        int x;
        moveonly(int x = -1) noexcept : x(x) {}
        moveonly(moveonly&& o) noexcept : x(o.x) { o = {}; }
        moveonly& operator=(moveonly o) noexcept { using std::swap; swap(x, o.x); return *this; }
    };
    
    static_assert(not std::is_copy_constructible{}, "moveonly");
    
    namespace bmi = boost::multi_index;
    using Table   = bmi::multi_index_container >
        > >;
    
    template 
    void dump(std::ostream& os, Container const& c) { 
        for (auto& r: c) os << r.x << " ";
        os << "\n";
    }
    
    moveonly pop_front(Table& table) {
        moveonly extracted;
    
        auto it = table.begin();
        if (it == table.end())
            throw std::logic_error("pop_front");
    
        if (table.modify(it, [&](moveonly& v) { extracted = std::move(v); })) {
            table.erase(it);
        }
    
        return extracted;
    }
    
    int main() {
        Table table;
    
        table.push_back({1});
        table.push_back({2});
        table.push_back({3});
    
        dump(std::cout << "table before: ", table);
    
        std::cout << "Extracted: " << pop_front(table).x << "\n";
    
        dump(std::cout << "table after: ", table);
    }
    

    Which prints:

    table before: 1 2 3 
    Extracted: 1
    table after: 2 3 
    

提交回复
热议问题