如何将项目从 boost::variant 移动到多地图?
Posted
技术标签:
【中文标题】如何将项目从 boost::variant 移动到多地图?【英文标题】:How do I move items from a boost::variant to a multimap? 【发布时间】:2017-12-04 22:44:46 【问题描述】:我想通过使用移动而不是复制来提高下面代码中PickPotatoes
的性能,但我不知道如何使用insert
和boost::variant
来做到这一点。在我的实际用例中,解析数据大约需要 75% 的时间,而真实版本的 PickPotatoes 大约需要 25% 的时间,原因是复制速度慢。通过改进PickPotatoes
,我应该能够做到这一点。是否可以从boost::variant
中移出某些内容并改进PickPotatoes
?
#include <map>
#include "boost/variant.hpp"
#include <string>
#include <vector>
#include <functional>
struct tuber
int z;
std::vector<double> r;
;
int getZ(const tuber& t)
return t.z;
boost::variant<std::string, tuber> GrowPotato()
int z = std::rand() / (RAND_MAX / 10);
if (z < 2)
return "BAD POTATO";
else
tuber ret;
ret.z = z;
ret.r.resize(10000);
for (int i = 0;i < 10000;++i)
ret.r[i] = std::rand() / (RAND_MAX / 50);
return ret;
std::vector<boost::variant<std::string,tuber>> GrowPotatoes(int n)
std::vector<boost::variant<std::string, tuber>> ret;
ret.resize(n);
for (int i = 0; i < n; ++i)
ret[i] = GrowPotato();
return ret;
//could make this more efficient.
std::pair<std::vector<std::string>,std::multimap<int, tuber>> PickPotatoes(std::vector <boost::variant<std::string, tuber>> result)
std::pair<std::vector<std::string>,std::multimap<int,tuber>> ret;
int numTypTwo = 0;
for (const auto& item : result)
numTypTwo += item.which();
ret.first.resize(result.size() - numTypTwo);
int fstSpot = 0;
for (int i = 0; i < result.size();++i)
if (result[i].which())
ret.second.insert(std::pair<int, tuber>(getZ(boost::get<tuber>(result[i])), boost::get<tuber>(result[i])));
else
ret.first[fstSpot++] = std::move(boost::get<std::string>(result[i]));
return ret;
int main()
std::srand(0);
std::vector<boost::variant<std::string, tuber>> q= GrowPotatoes(5000);
std::pair<std::vector<std::string>, std::multimap<int, tuber>> z = PickPotatoes(q);
return 0;
【问题讨论】:
考虑使用boost::optional<tuber>
而不是boost::variant<std::string, tuber>
。它使您的意图更加清晰。
为什么要优化pick-potato? i.imgur.com/NWKeaBd.png。如果"BAD POTATO"
是“未解析”的源片段,是否可以使用 string_view 来消除分配?
因为这是我真实代码中的瓶颈所在。这只是一个工作示例,您可以假装 growPotato 高效。
【参考方案1】:
最简单的方法是移动参数值:
std::pair<std::vector<std::string>, std::multimap<int, tuber>> z = PickPotatoes(std::move(q));
确实,它赢得了 14% 的性能,大致在我的基准测试中。其余的在很大程度上取决于它的全部含义以及如何使用它。
专注于减少分配(如果可以,请使用非基于节点的容器,例如boost::flat_multimap
,显式排序,使用 string_view,解析为所需的数据结构而不是中间数据结构)。
奖金
我可以通过以下方式剃掉大约 30%:
std::pair<std::vector<std::string>, std::multimap<int, tuber> >
PickPotatoes(std::vector<boost::variant<std::string, tuber> >&& result)
std::pair<std::vector<std::string>, std::multimap<int, tuber> > ret;
ret.first.reserve(result.size());
struct Vis
using result_type = void;
void operator()(std::string& s) const
first.emplace_back(std::move(s));
void operator()(tuber& tbr) const
second.emplace(tbr.z, std::move(tbr));
std::vector<std::string>& first;
std::multimap<int, tuber>& second;
visitor ret.first, ret.second ;
for (auto& element : result)
boost::apply_visitor(visitor, element);
return ret;
使用emplace,避免重复get<>
,避免循环获取first
大小等
【讨论】:
设法削减了一些更微不足道的边距。真的,如果可以,请专注于更大的目标。 哦,好漂亮。谢谢。以上是关于如何将项目从 boost::variant 移动到多地图?的主要内容,如果未能解决你的问题,请参考以下文章
使用 boost::variant 库制作地图。如何将事物存储和显示为正确的类型?
利用 boost-variant 创建带有 boost::mpl::for_each 的通用工厂方法
如何返回由 boost::variant 返回类型中包含的类型的子集组成的 boost::variant