Таинственное поведение unordered_map в Visual Studio - PullRequest
12 голосов
/ 28 июля 2011

Я хочу хранить ~ 3 000 000 double значений с индексами unsigned int в VS2010 C ++. Я использую std::tr1:unordered_map<unsigned int, double> для этой цели. К сожалению, когда я пытаюсь сохранить значение с номером 2 ^ 21, выдается исключение (как будто есть место только для 2 ^ 21-1, т. Е. Некоторый индекс может использовать только 20 бит). Я пытался rehash перед сохранением значений, которые тоже не работали.

Наконец я закончил с какой-то очень простой тестовой программой (которая показала даже немного другое поведение, но в любом случае):

    std::tr1::unordered_map<unsigned int, float> mapOut;
    //mapOut.rehash(SOMESIZE);
    for (unsigned int i=0; i<3000000; i++)
    {
        if (i%1000==0) std::cout << i << std::endl;
        mapOut[i] = 0.0;
    }

В некоторых случаях я проверял:

1) Если я вообще не перефразирую, программа делает длинный перерыв после вывода в соответствии с i == 32000 (в конечном итоге 2 ^ 15), а затем продолжает i == 262000 (2 ^ 18). Там он держится вечно (при 100% загрузке процессора, память не увеличивается).

2) Если я сделаю rehash(1000), то получится i == 65000 (2 ^ 16) и будет держаться вечно (загрузка процессора 100%, память не увеличивается).

3) Если я выполняю rehash(3000000), цикл успешно завершается, но программа никогда не завершается, т. Е., Очевидно, существует некоторая проблема с деструктором.

Что там происходит, и что еще важнее: что мне с этим делать?!

Большое спасибо за вашу помощь!

1 Ответ

4 голосов
/ 28 июля 2011

Следующая ошибка в Connect, похоже, связана с вашей проблемой: Visual C ++: std :: unordered_map Производительность деструктора в конфигурации отладки

Та же проблема возникает не только в деструкторе,но также, когда unordered_map изменяется.Кажется, что-то связано с аннулированием итераторов, если включена отладка итераторов.

Говорят, что это было исправлено для VC11.В списке также есть несколько обходных путей, но я их не пробовал.

Очень простой способ решения проблемы производительности как для отладочной, так и для релизной сборок - установить _SECURE_SCL=0 и _HAS_ITERATOR_DEBUGGING=0 в параметрах проекта.в разделе «Параметры конфигурации / C / C ++ / Препроцессор / Определения препроцессора», который полностью отключает отладку всех итераторов.Это также отключает некоторые проверки безопасности, поэтому вам нужно быть более осторожным в своем собственном коде.Я полагаю, что оба они уже используются по умолчанию при сборке релизов, поэтому вам не нужно ничего там менять.

Похоже, это связано с проблемой вашего примера кода.Я не уверен насчет первоначальной проблемы, поскольку вы не сказали, какое исключение было выдано.

...