c++ - 有没有办法从ordered_index ed multi_index 中移动一个元素?
问题描述
从 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
0x55fdda3272e0
修改 lambda 返回后,容器访问从对象 ( ) 移出。我认为这是为了重新排序。modify()
不知道我用modify()
with erase()
。对于random_access_index
,它工作得很好,因为容器不需要重新排序,但它不适用于ordered_index
.
有什么办法可以从ordered_index
ed中移动一个元素multi_index
?
解决方案
您可以使用以下内容从一段时间中提取一个值,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);
}
完整的例子如下。
#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
推荐阅读
- amazon-web-services - aws dynamodb 流 lambda 处理速度太快
- java - 在私有方法中保存实体
- couchdb - 有没有办法获得特定的修订?
- javascript - 如何使用 Jest 和/或 Enzyme 测试由 React 组件呈现的样式和媒体查询
- javascript - 选择单个数据类型数组 Javascript
- javascript - React Js AwesmeSlider 自动播放
- sql - 用合并语句替换当前表
- vue.js - 为什么 axios delete 不能按我的意愿工作,如何解决?
- spinnaker - Spinnaker:如何将自定义 boms 带入 Spinnaker pod 以便能够使用 hal 部署它?
- reactjs - React App - 上下文“路由器”在“LinkContainer”中标记为必需,但其值为“未定义”