[英]Move element from boost multi_index array
Let's say I have movable and not copyable object and I have boost multi-index array with random_access index. 假设我有可移动而不是可复制的对象,并且我使用random_access索引来提升多索引数组。 I need to move my object out of array front, but I cannot find any method, that would give me rvalue/lvalue reference in documentation .
我需要将我的对象移出数组前面,但我找不到任何方法,这会在文档中给出rvalue / lvalue引用。 I can only see
front()
which gives me constant reference and pop_front()
which erases element, but does not return anything. 我只能看到
front()
给我常量引用和pop_front()
,它擦除元素,但不返回任何东西。 So is there a way to move element out of boost multi-index? 那么有没有办法将元素从boost多指数中移出?
Adding to @sehe's answer, the following shows how to modify the code in case your moveable type is not default constructible: 添加到@ sehe的答案,以下显示了如果您的可移动类型不是默认可构造的,如何修改代码:
Edited: changed code to properly deal with destruction of *extracted
. 编辑:更改代码以正确处理
*extracted
破坏。
Edited: added alternative with std::unique_ptr
. 编辑:使用
std::unique_ptr
添加替代方案。
Edited: added a second altrnative by sehe . 编辑:由sehe添加第二个altrnative 。
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <iostream>
#include <type_traits>
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>{}, "moveonly");
namespace bmi = boost::multi_index;
using Table = bmi::multi_index_container<moveonly,
bmi::indexed_by<
bmi::random_access<bmi::tag<struct _ra> >
> >;
template <typename Container>
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<sizeof(moveonly), alignof(moveonly)>::type buffer;
moveonly* extracted = reinterpret_cast<moveonly*>(&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: 使用
std::unique_ptr
进行清理也是如此:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <iostream>
#include <memory>
#include <type_traits>
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>{}, "moveonly");
namespace bmi = boost::multi_index;
using Table = bmi::multi_index_container<moveonly,
bmi::indexed_by<
bmi::random_access<bmi::tag<struct _ra> >
> >;
template <typename Container>
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<sizeof(moveonly), alignof(moveonly)>::type buffer;
moveonly* extracted = reinterpret_cast<moveonly*>(&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<moveonly,void(*)(moveonly*)> 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: Sehe提供了另一种基于
boost::optional
替代方案,它是最优雅的:
#include <boost/multi_index_container.hpp>
#include <boost/optional.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <iostream>
#include <memory>
#include <type_traits>
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>{}, "moveonly");
namespace bmi = boost::multi_index;
using Table = bmi::multi_index_container<moveonly,
bmi::indexed_by<
bmi::random_access<bmi::tag<struct _ra> >
> >;
template <typename Container>
void dump(std::ostream& os, Container const& c) {
for (auto& r: c) os << r.x << " ";
os << "\n";
}
moveonly pop_front(Table& table) {
boost::optional<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 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);
}
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. 不支持非const元素操作,因为它们可能使元素处于一种状态,该状态会破坏各种索引对它们的不变量。
The closest thing you can do is using modify
: 你最接近的是使用
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. 请注意,
modify
会产生检查所有索引的成本,并且可能会失败。 Fortunately, if it does fail, the effect is that iterator
is erased: 幸运的是,如果确实失败了,那么效果是
iterator
被删除:
- 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.
效果:调用mod(e),其中e是position指向的元素,并将* position重新排列到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: 这是一个现场演示:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <iostream>
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>{}, "moveonly");
namespace bmi = boost::multi_index;
using Table = bmi::multi_index_container<moveonly,
bmi::indexed_by<
bmi::random_access<bmi::tag<struct _ra> >
> >;
template <typename Container>
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.