将C ++插入map()需要很长时间

时间:2019-07-10 13:04:54

标签: c++ dictionary object pointers insert

我有一个map类型的<int, foo*>,我正在从数据库中填充。 int是唯一键,因此在填充之前,我要检查是否在地图中已经创建了键foo并将其插入地图中。

foo类还具有另一个类型为<int, float>的映射作为属性,也需要从数据库中填充。我有下面的代码,据说很简单:

std::map<int, foo> MAP;

while(getline(infile, line))
{ //reading records in data file
    string item;
    stringstream ss(line);
    vector<string> splittedString;

    int a = stoi(splittedString[0]); // cells after splitting data
    int b = stoi(splittedString[1]);
    float c = stof(splittedString[2]);


    if (MAP.find(a) == MAP.end())
    {
        foo f = foo();
        MAP.insert({a, &f});
        f.fooMap.insert({b, c/100});
    }
    else
    {
        foo* f = MAP.at(a);
        f->fooMap.insert({b, c/100});
    }
}

这花了很多时间来计算。大约有50,000条记录,但这不会永远保留。我很确定自己做错了,因为我对c ++有点生疏。

我知道创建foo对象时存在一些冗余,并且我认为执行上述操作的更有效方法是以下“错误”代码:

while(getline(infile, line))
{//reading records in data file
    string item;
    stringstream ss(line);
    vector<string> splittedString;

    int a = stoi(splittedString[0]); //cells after splitting data
    int b = stoi(splittedString[1]);
    float c = stof(splittedString[2]);

    foo f = *MAP[a];        
    if (f == NULL)
    {
        f = foo();
        MAP.insert({a, &f});

    }    
    f->fooMap.insert({b, c/100});
}

更新

如果我使用MAP<int, foo>而不是MAP<int, foo*>(并相应地安排了插入代码),则该代码可以正常工作。所以我在用指针做错了。解决此问题的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

您的代码要复杂得多。您应该让std::map进行工作,而不要自己尝试。您需要的是容器的.emplace函数。它不仅跳过了不必要的插入操作,而且还为您提供了正确的修改条目。例如,您可以执行以下操作:

#include <iostream>
#include <map>
#include <string>

int main()
{
    //helper
    auto print = [](auto MAP) 
    {
        std::cout << "MAP:\n";
        for (auto && each : MAP)
            std::cout << each.first << "->" << each.second << '\n';
    };
    //work
    std::map<int, std::string> MAP;

    MAP.emplace(1,"").first->second = "one";
    MAP.emplace(2,"").first->second = "two";
    print(MAP);
    MAP.emplace(1,"").first->second = "three";
    print(MAP);
}

哪个会产生以下输出:

MAP:
1->one
2->two
MAP:
1->three
2->two

当然,这具有奇怪的.first->second语法,但是我们可以将其重构为新的lambda:

auto update = [](auto& MAP, auto index, auto entry) 
{
    MAP.emplace(index,"").first->second = entry;
};

可让您编写以下内容:

update(MAP, 1, "one");
update(MAP, 2, "two");
print(MAP);
update(MAP, 1, "three");
print(MAP);

编辑

因为您要求的是std::unique_ptr解决方案,所以就这样:

#include <iostream>
#include <map>
#include <string>
#include <memory>

int main()
{
    //helper
    auto print = [](const auto& MAP) 
    {
        std::cout << "MAP:\n";
        for (auto && each : MAP)
            std::cout << each.first << "->" << *each.second.get() << '\n';
    };
    //work
    std::map<int, std::unique_ptr<std::string>> MAP;

    auto update = [](auto& MAP, auto index, auto entry) 
    {
        *MAP.emplace(index, std::make_unique<std::string>()).first->second.get() = entry;
    };
    update(MAP, 1, "one");
    update(MAP, 2, "two");
    print(MAP);
    update(MAP, 1, "three");
    print(MAP);
}

不幸的是,由于std::unique_ptr无法复制,因此有点难以理解。 (这只是它的实现方式。)