# V708. Dangerous construction is used: 'm[x] = m.size()', where 'm' is of 'T' class. This may lead to undefined behavior.

Анализатор обнаружил в коде программы случай неопределённого поведения, связанного с контейнерами типа map или схожими с ним.

Пример некорректного кода:

    std::map<size_t, size_t> m;
    ....
    m[0] = m.size();

Этот пример приводит к неопределённому поведению, поскольку порядок вычисления операндов у оператора присваивания не определён. В случае, если в объекте уже существует элемент, ассоциированный с нулём, то проблем не возникнет. Однако в случае его отсутствия действия программы могут пойти по двум различным сценариям в зависимости от версии компилятора, операционной системы и так далее.

Предположим, что компилятор сначала вычисляет правый операнд и лишь потом – левый операнд операции присваивания. Поскольку контейнер пуст, m.size() возвращает ноль. Затем с нулём ассоциируется ноль. В итоге имеем, что m[0] == 0.

Теперь предположим, что компилятор сначала вычисляет левый операнд и лишь потом – правый. Сначала будет взят m[0]. Поскольку с нулём ничего не ассоциировано, будет создана пустая ассоциация. Затем вычисляется m.size(). Поскольку контейнер уже не пуст, m.size() возвращает единицу. После этого единица ассоциируется с нулём. В итоге имеем, что m[0] == 1.

Правильным решением для исправления кода будет использования временной переменной и заранее связать какое-то значение с нулём:

    std::map<size_t, size_t> m;
    ....
    m[0] = 0;
    const size_t mapSize = m.size();
    m[0] = mapSize;

Несмотря на то, что данная ситуация может возникать достаточно редко в реальном коде, она опасна тем, что фрагмент кода, приводящий к неопределённому поведению, часто очень сложно выявить.

Данная диагностика классифицируется как:

CWE-758 CERT-EXP50-CPP

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V708.