插入到运行时挂起的 unordered_map

时间:2021-08-01 21:53:50

标签: c++ debugging

我遇到了一个我只能形容为完全不熟悉的问题,我可以寻求帮助。就上下文而言,我对 C++ 编程了解不多,我正在努力学习更多,因此我目前正在编写的代码比其他任何东西都更具教育意义。我想创建一个 unordered_map,它包含一个字符串作为键和一个向量作为键的关联值。传统上,这将是微不足道的。但是,我的程序正在尝试将 json 数据解析为这个 unordered_map 数据结构,并且无法保证预先知道每个向量的类型。我唯一可以保证的是每个向量的类型将是以下类型集中的类型之一:string, int, double。为了尝试实现以这种方式运行的 unordered_map,我尝试使用 variant,但目前该变体实现导致超时错误。我希望得到一些关于超时原因的建议,最好是如何解决它。

代码如下(复制此问题的最小示例):


#include <nlohmann/json.hpp>
#include <unordered_map>
#include <variant>
#include <iostream>
#include <string> 

using json = nlohmann::json;

int main() {
// map stores col name as string and vector with col type
    std::unordered_map<std::string, std::vector<std::variant<double, long, std::string>>> mp;

   // input is type nlohmann::json
   json input = "{ \"happy\": \"yes\", \"pi\": 3.141, \"t\": 1608008400000 }"_json;

   for(auto& el : input.items()) { 
       if (mp.find(el.key()) == mp.end()) {
           std::cout << "trying insertion for key " << el.key() << std::endl;
           mp.insert({ el.key(), std::vector<std::variant<double, long, std::string>>{ el.value() } });
           std::cout << "inserted " << el.key() << " successfully!" << std::endl;
       }
    }
    return 0;
}

这是我的输入(请注意,我的输入以 nlohmann::json 类型传递给此程序): {"c":127.88,"h":127.9,"l":124.13,"n":867462,"o":124.34,"t":1608008400000,"v":157572262.0,"vw":126.5535},{"c":127.81,"h":128.37,"l":126.56,"n":550012,"o":127.41,"t":1608094800000,"v":95913591.0,"vw":127.5459}

这是当前的输出:

And here is the current output

inserted c successfully!
trying insertion for key h
inserted h successfully!
trying insertion for key l
inserted l successfully!
trying insertion for key n
inserted n successfully!
trying insertion for key o
inserted o successfully!
trying insertion for key t
[1]    40305 killed     ./test

我已尝试解决有关为什么会发生这种情况的一系列潜在不同问题,但我基本上已经通过反复试验确认,当我尝试将 std::variant<std::string, long, double> 用于我的向量类型时会出现此问题。当我为所有向量分配一个统一类型(例如,double)时,所有插入都可以正常工作。然而,问题是可扩展性之一。尽管这个例子只包含双精度和长整数,但我希望将来能够解析一些看起来像这样的数据: {"a": "test", "b": 1243.343, "c": 120910394023332} 没有错误并且返回值是(为了清楚起见显示了类型):

a : vector<string>{"test"}, b : vector<double>{1243.343}, c : vector<long>{120910394023332}

如果有什么我能澄清的可以帮助回答这个问题,请告诉我,我会添加进去。

2 个答案:

答案 0 :(得分:2)

以下向量声明:

std::vector<int> v{4};

这将创建一个默认初始化为 4 个值的向量。这个重载的 std::vector 构造函数接受一个参数,该参数给出了向量的初始大小。

std::vector<std::variant<double, long, std::string>>{ el.value() } }

记住我的介绍,现在应该很明显这将调用相同的构造函数。

当我在调试器中逐步执行上述代码时,我的调试器揭示了这样一个事实:当 1608008400000 被传递到构造函数时,事情很快就变得松散了。我的计算机成功创建具有一万亿、六千八十亿、八百万和四十万值的向量的机会非常非常渺茫。

el.value() 不返回变体。它返回一个 JSON 值,并且没有现成的机制将其转换为变体。您必须自己完成所有工作,例如:

   auto v=el.value();

   if (v.is_number())
   {
       if (v.is_number_float())
       {
           vv.emplace_back( (double)v);
       }
       else
       {
           vv.emplace_back( (long)v);
       }
   }
   else
   {
       vv.emplace_back( (std::string) v);
   }

   mp.insert({ el.key(), vv});

答案 1 :(得分:1)

我已经设法回答了我自己的问题(尽管是以迂回的方式)。我可以使用 is_number_integer() 中的 nlohmann::json 函数检查类型是否为整数。从那里,如果它是一个整数,我可以从中获取 uint64_t 值,然后将其插入到变体向量中。我必须进行的唯一修改是通过删除 long 并添加 uint64_t 来更改变体向量以更改可用类型。这是新代码:

int main() {
// map stores col name as string and vector with col type
    std::unordered_map<std::string, std::vector<std::variant<double, uint64_t, std::string>>> mp;

   // input is type nlohmann::json
   // input.push_back(json::object_t::value_type("t", 1608008400000));
   json input = "{ \"happy\": true, \"pi\": 3.141, \"t\": 1608008400000 }"_json;


   for(auto& el : input.items()) {
       if (mp.find(el.key()) == mp.end()) {
            std::cout << "trying insertion for key " << el.key() << std::endl;
            std::cout << "value is " << el.value() << " with type " << el.value().type_name() << std::endl;
            if (el.value().is_number_integer()) {
                mp.insert({ el.key(), std::vector<std::variant<double, uint64_t, std::string>>{ el.value().get<std::uint64_t>() } });
            }
            else {
                mp.insert({ el.key(), std::vector<std::variant<double, uint64_t, std::string>>{ el.value() } });
            }
            std::cout << "inserted " << el.key() << " successfully!" << std::endl;
       }
    }
    return 0;
}