Ошибка конструктора перемещения unordered_set/map в VC10?

Похоже, что конструкторы перемещения unordered_set/map в VC10 (Visual Studio 2010) переводят правую часть в неопределенное состояние после вызова, что приводит к сбою других операций (таких как «вставка»). Операторы присваивания перемещения работают нормально. Однако нормальный набор/карта, кажется, ведет себя правильно во всех случаях. Кроме того, все работает нормально в VC11 (Visual Studio 2012).

Это ошибка реализации _Hash в VC10 или я что-то упускаю? Заранее спасибо за любой вклад!

#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>

std::set<int> si0;
std::unordered_set<int> usi0;

std::map<int, int> mii0;
std::unordered_map<int, int> umii0;

int _tmain(int argc, _TCHAR* argv[])
{
    si0.insert(0);
    si0.insert(1);
    si0.insert(2);
    std::set<int> si( std::move(si0) ); // fine!
    si0.insert(666);

    usi0.insert(0);
    usi0.insert(1);
    usi0.insert(2);
    //std::unordered_set<int> usi( std::move(usi0) ); // this seems to put usi0 to an undefined state, which makes 'insert' below cry!
    std::unordered_set<int> usi; usi = std::move(usi0); // this works!
    usi0.insert(666);

    mii0[0] = 0;
    mii0[1] = 1;
    mii0[2] = 2;
    std::map<int, int> mii( std::move(mii0) ); // fine!
    mii0[666] = 666;

    umii0[0] = 0;
    umii0[1] = 1;
    umii0[2] = 2;
    //std::unordered_map<int, int> umii( std::move(umii0) ); // this seems to put umii0 to an undefined state, which makes 'insert' below cry!
    std::unordered_map<int, int> umii; umii = std::move(umii0); // this works!
    umii0[666] = 666;

    return 0;
}

person Lin    schedule 08.10.2012    source источник


Ответы (1)


Хорошо, покопавшись в реализации класса _Hash в VC10 и сравнив ее с реализацией в VC11, я заметил, что конструктор перемещения класса _Hash в VC10 никогда не инициализирует свой член '_Max_bucket_size', а затем логика заменяет это неинициализированное значение на правая часть (перемещенный экземпляр _Hash), оставив правую часть в неинициализированном состоянии.

Это нормально, если правая часть конструктора перемещения действительно является временным объектом, но моя логика полагается на то, что конструктор перемещения «сбрасывает» объект правой стороны, после чего объект правой стороны будет реконструирован.

Версия с назначением перемещения работает в том смысле, что она требует, чтобы объект с левой стороны был каким-то образом правильно сконструирован (в данном случае сконструирован по умолчанию, с правильно инициализированным '_Max_bucket_size'), а при замене его на правую сторону правая сторона не оставил в плохом состоянии. Тем не менее, оставление правой части, принимающей состояние подкачки из левой части, не соответствует стандартному поведению оператора присваивания перемещения, который должен сбрасывать правую часть, которая делает нечто большее, чем просто перестановка. !

Соответствующая реализация в VC11, похоже, исправила поведение и соответствует стандарту.

person Lin    schedule 08.10.2012