从boost multi_index数组移动元素 [英] Move element from boost multi_index array
问题描述
比方说,我有可移动且不可复制的对象,并且我具有带有random_access索引的boost-multi-index数组.我需要将对象移出数组前端,但找不到任何方法,该方法会在
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 any method, that would give me rvalue/lvalue reference in documentation. I can only see front()
which gives me constant reference and pop_front()
which erases element, but does not return anything. So is there a way to move element out of boost multi-index?
推荐答案
在@sehe的答案中,以下内容显示了在您的可移动类型不能默认构造的情况下如何修改代码:
Adding to @sehe's answer, the following shows how to modify the code in case your moveable type is not default constructible:
已编辑:更改了代码以正确处理对*extracted
的破坏.
已编辑:添加了std::unique_ptr
替代项.
编辑:通过 sehe 添加了第二个替代字词.
Edited: changed code to properly deal with destruction of *extracted
.
Edited: added alternative with std::unique_ptr
.
Edited: added a second altrnative by sehe.
#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);
}
使用std::unique_ptr
进行清理的相同内容:
Same thing using std::unique_ptr
for cleanup:
#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 提供了另一种基于boost::optional
的替代方法,它是所有方法中最优雅的:
Sehe provides yet another alternative based on boost::optional
which is the most elegant of all:
#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);
}
这篇关于从boost multi_index数组移动元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!