如何将项目从 boost::variant 移动到多地图?

Posted

技术标签:

【中文标题】如何将项目从 boost::variant 移动到多地图?【英文标题】:How do I move items from a boost::variant to a multimap? 【发布时间】:2017-12-04 22:44:46 【问题描述】:

我想通过使用移动而不是复制来提高下面代码中PickPotatoes 的性能,但我不知道如何使用insertboost::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&lt;tuber&gt; 而不是boost::variant&lt;std::string, tuber&gt;。它使您的意图更加清晰。 为什么要优化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&lt;&gt;,避免循环获取first大小等

【讨论】:

设法削减了一些更微不足道的边距。真的,如果可以,请专注于更大的目标。 哦,好漂亮。谢谢。

以上是关于如何将项目从 boost::variant 移动到多地图?的主要内容,如果未能解决你的问题,请参考以下文章

使用 boost::variant 库制作地图。如何将事物存储和显示为正确的类型?

利用 boost-variant 创建带有 boost::mpl::for_each 的通用工厂方法

如何返回由 boost::variant 返回类型中包含的类型的子集组成的 boost::variant

boost::variant 如何存储引用?

Boost::Variant "Error: no match for call to [...]" 访问者操作符重载

如何在 boost::variant<T> 中存储引用而不是复制对象?