Move element from boost multi_index array

后端 未结 2 689
天命终不由人
天命终不由人 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条回答
  •  粉色の甜心
    2020-12-04 00:34

    Adding to @sehe's answer, the following shows how to modify the code in case your moveable type is not default constructible:

    Edited: changed code to properly deal with destruction of *extracted.
    Edited: added alternative with std::unique_ptr.
    Edited: added a second altrnative by sehe.

    Live On Coliru

    #include 
    #include 
    #include 
    #include 
    
    struct moveonly {
        int x;
        moveonly(int x) noexcept : x(x) {}
        moveonly(moveonly&& o) noexcept : x(o.x) { o = {-1}; }
        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) {
        std::aligned_storage::type buffer;
        moveonly* extracted = reinterpret_cast(&buffer);
    
        auto it = table.begin();
        if (it == table.end())
            throw std::logic_error("pop_front");
    
        if (table.modify(it, [&](moveonly& v) { new (extracted) moveonly{std::move(v)}; })) {
            table.erase(it);
        }
    
        try {
            moveonly ret = std::move(*extracted);
            extracted->~moveonly();
            return ret;
        } catch(...) {
            extracted->~moveonly();
            throw;
        }
    }
    
    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);
    }
    

    Same thing using std::unique_ptr for cleanup:

    Live On Coliru

    #include 
    #include 
    #include 
    #include 
    #include 
    
    struct moveonly {
        int x;
        moveonly(int x) noexcept : x(x) {}
        moveonly(moveonly&& o) noexcept : x(o.x) { o = {-1}; }
        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) {
        std::aligned_storage::type buffer;
        moveonly* extracted = reinterpret_cast(&buffer);
    
        auto it = table.begin();
        if (it == table.end())
            throw std::logic_error("pop_front");
    
        if (table.modify(it, [&](moveonly& v) { new (extracted) moveonly{std::move(v)}; })) {
            table.erase(it);
        }
    
        std::unique_ptr ptr = {
            extracted,
            [](moveonly* p){ p->~moveonly(); }
        };
    
        return std::move(*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);
    }
    

    Sehe provides yet another alternative based on boost::optional which is the most elegant of all:

    Live On Coliru

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    struct moveonly {
        int x;
        moveonly(int x) noexcept : x(x) {}
        moveonly(moveonly&& o) noexcept : x(o.x) { o = {-1}; }
        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) {
        boost::optional 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 std::move(*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);
    }
    

提交回复
热议问题