C ++ вставка в map () занимает много времени - PullRequest
0 голосов
/ 10 июля 2019

У меня есть 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});
    }
}

Это занимает смешное количество времени, чтобы вычислить. Есть около 50000 записей, но это не должно длиться вечно. Я почти уверен, что делаю что-то не так, так как я немного заржавел с 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 голосов
/ 10 июля 2019

Ваш код немного сложнее, чем нужно. Вы должны позволить 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, но мы можем преобразовать его в новую лямбду:

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);

EDIT

Поскольку вы запросили решение 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 не может быть скопировано. (Это так, как это реализовано.)

...