【问题标题】:Is there any way to move an element from ordered_index ed multi_index?有没有办法从ordered_index ed multi_index 中移动一个元素?
【发布时间】:2019-08-03 03:06:32
【问题描述】:

自 C++17 起,std::set 具有支持从容器中移动节点的extract() 成员函数。这是一个示例代码:

#include <iostream>
#include <cassert>
#include <set>

struct trace {
    trace() {
        std::cout << this << ":" << " construct" << std::endl;
    }
    ~trace() {
        std::cout << this << ":" << " destruct" << std::endl;
    }
    trace(trace& other) {
        std::cout << this << ":" << " copy construct from " << &other << std::endl;
    }
    trace(trace&& other) {
        std::cout << this << ":" << " move construct from " << &other << std::endl;
    }
    trace& operator=(trace const& other) {
        std::cout << this << ":" << " copy assign from    " << &other << std::endl;
        return *this;
    }
    trace& operator=(trace&& other) {
        std::cout << this << ":" << " move assign from    " << &other << std::endl;
        return *this;
    }
};

inline bool operator<(trace const& lhs, trace const& rhs) {
    std::cout << &lhs << " < " << &rhs << std::endl;
    return &lhs < &rhs;
}

int main () {
    std::set<trace> s;
    s.insert(trace());
    s.insert(trace());
    s.insert(trace());
    auto it = s.begin();
    ++it;

    assert(s.size() == 3);
    std::cout << "[[extract]]" << std::endl;
    trace t = std::move(s.extract(it).value());
    assert(s.size() == 2);
}

运行演示:https://wandbox.org/permlink/ZZHkZV1DUZpM3YrU

我得到了以下结果:

0x7ffd30bbfbd0: construct
0x55edd361d2a0: move construct from 0x7ffd30bbfbd0
0x7ffd30bbfbd0: destruct
0x7ffd30bbfbc8: construct
0x7ffd30bbfbc8 < 0x55edd361d2a0
0x55edd361d2a0 < 0x7ffd30bbfbc8
0x7ffd30bbfbc8 < 0x55edd361d2a0
0x55edd361d2d0: move construct from 0x7ffd30bbfbc8
0x7ffd30bbfbc8: destruct
0x7ffd30bbfbc0: construct
0x7ffd30bbfbc0 < 0x55edd361d2a0
0x7ffd30bbfbc0 < 0x55edd361d2d0
0x55edd361d2d0 < 0x7ffd30bbfbc0
0x7ffd30bbfbc0 < 0x55edd361d2d0
0x55edd361d300: move construct from 0x7ffd30bbfbc0
0x7ffd30bbfbc0: destruct
[[extract]]
0x7ffd30bbfbb0: move construct from 0x55edd361d2d0
0x55edd361d2d0: destruct
0x7ffd30bbfbb0: destruct
0x55edd361d300: destruct
0x55edd361d2a0: destruct

[[extract]] 之后,容器无法访问从对象移动。没关系。

我正在寻找在 boost::multi_index 上做同样事情的方法。

我尝试了与以下问答相同的方法: Move element from boost multi_index array

我尝试了同样的方法:

namespace mi = boost::multi_index;

using mi_trace = mi::multi_index_container<
    trace,
    mi::indexed_by<
        mi::ordered_unique<
            mi::identity<trace>
        >
    >
>;

int main () {
    mi_trace mi;

    mi.insert(trace());
    mi.insert(trace());
    mi.insert(trace());

    auto it = mi.begin();
    ++it;

    assert(mi.size() == 3);
    std::optional<trace> target;
    std::cout << "[[modify]]" << std::endl;
    if (mi.modify(
            it,
            [&](auto& e) {
                target.emplace(std::move(e));
            }
        )
    ) {
        std::cout << "[[erase]]" << std::endl;
        mi.erase(it);
        assert(mi.size() == 2);
    }
}

运行演示:https://wandbox.org/permlink/eKpGDpMBbx5aRz9O

得到以下输出:

[[modify]]
0x7fffe1f77c66: move construct from 0x55fdda3272e0
0x55fdda3272b0 < 0x55fdda3272e0
0x55fdda3272e0 < 0x55fdda327310
[[erase]]
0x55fdda3272e0: destruct
0x7fffe1f77c66: destruct
0x55fdda3272b0: destruct
0x55fdda327310: destruct

multi_index 容器访问在修改 lambda 返回后从对象 (0x55fdda3272e0) 移动。我认为这是为了重新排序。 modify() 不知道我使用 modify()erase()。对于random_access_index,它运行良好,因为容器不需要重新排序,但它不适用于ordered_index

有没有办法从ordered_indexed multi_index 移动元素?

【问题讨论】:

  • 很难理解你的问题。让我们来看第一部分 - 输出对我来说看起来不错。你期望什么输出?
  • 第一部分输出没问题。最后一个输出不好,因为移动后访问了0x55fdda3272e0。
  • 我想使用boost::muti_index有序索引做与std::set::extract相同的事情。
  • 我仍然不确定您要达到什么目标。你有迭代器it,它指向你需要的元素,如果你要从中移动什么——只需从容器中移动并删除它。这有什么问题?
  • 是的,确实有道理。

标签: c++ boost extract multi-index


【解决方案1】:

您可以使用以下方法从 multi_index_container 中提取值,同时确保在提取值后立即删除该元素:

struct extract_value_exception{};

template<typename MultiIndexContainerIndex>
auto extract_value(
    MultiIndexContainerIndex& i,
    typename MultiIndexContainerIndex::iterator it)
{
    using value_type = typename MultiIndexContainerIndex::value_type;

    std::optional<value_type> o;
    try{
        i.modify(it, [&](value_type& x){
            o.emplace(std::move(x));
            throw extract_value_exception{};
        });
    }
    catch(const extract_value_exception&){}
    return std::move(*o);
}

完整的例子如下。

Live On Wandbox

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <cassert>
#include <iostream>
#include <optional>

struct trace {
    trace() {
        std::cout << this << ":" << " construct" << std::endl;
    }
    ~trace() {
        std::cout << this << ":" << " destruct" << std::endl;
    }
    trace(trace& other) {
        std::cout << this << ":" << " copy construct from " << &other << std::endl;
    }
    trace(trace&& other) {
        std::cout << this << ":" << " move construct from " << &other << std::endl;
    }
    trace& operator=(trace const& other) {
        std::cout << this << ":" << " copy assign from    " << &other << std::endl;
        return *this;
    }
    trace& operator=(trace&& other) {
        std::cout << this << ":" << " move assign from    " << &other << std::endl;
        return *this;
    }
};

inline bool operator<(trace const& lhs, trace const& rhs) {
    std::cout << &lhs << " < " << &rhs << std::endl;
    return &lhs < &rhs;
}

struct extract_value_exception{};

template<typename MultiIndexContainerIndex>
auto extract_value(
    MultiIndexContainerIndex& i,
    typename MultiIndexContainerIndex::iterator it)
{
    using value_type = typename MultiIndexContainerIndex::value_type;

    std::optional<value_type> o;
    try{
        i.modify(it, [&](value_type& x){
            o.emplace(std::move(x));
            throw extract_value_exception{};
        });
    }
    catch(const extract_value_exception&){}
    return std::move(*o);
}

int main () {
    boost::multi_index_container<trace> s;
    s.insert(trace());
    s.insert(trace());
    s.insert(trace());
    auto it = s.begin();
    ++it;

    assert(s.size() == 3);
    std::cout << "[[extract]]" << std::endl;
    trace t = extract_value(s, it);
    assert(s.size() == 2);
}

输出

0x7ffd5feed89d: construct
0x21f7190: move construct from 0x7ffd5feed89d
0x7ffd5feed89d: destruct
0x7ffd5feed89e: construct
0x7ffd5feed89e < 0x21f7190
0x21f7190 < 0x7ffd5feed89e
0x21f71c0: move construct from 0x7ffd5feed89e
0x7ffd5feed89e: destruct
0x7ffd5feed89f: construct
0x7ffd5feed89f < 0x21f7190
0x7ffd5feed89f < 0x21f71c0
0x21f71c0 < 0x7ffd5feed89f
0x21f71f0: move construct from 0x7ffd5feed89f
0x7ffd5feed89f: destruct
[[extract]]
0x7ffd5feed836: move construct from 0x21f71c0
0x21f71c0: destruct
0x7ffd5feed867: move construct from 0x7ffd5feed836
0x7ffd5feed836: destruct
0x7ffd5feed867: destruct
0x21f7190: destruct
0x21f71f0: destruct

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2021-09-17
  • 2010-12-11
  • 1970-01-01
  • 2020-05-05
  • 1970-01-01
  • 2018-10-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多