Подтвердить что ты не робот

Определено ли это поведение кода?

Что выводит следующий код на консоль?

map<int,int> m;
m[0] = m.size();
printf("%d", m[0]);

Возможные ответы:

  • Поведение кода не определено, поскольку он не определен, какой оператор m[0] или m.size() выполняется сначала компилятором. Поэтому он может печатать 1, а также 0.
  • Он печатает 0, потому что выполняется правая часть оператора присваивания.
  • Он печатает 1, потому что operator[] имеет наивысший приоритет для полного оператора m[0] = m.size(). Из-за этого происходит следующая последовательность событий:

    • m[0] создает новый элемент на карте
    • m.size() получает вызов, который теперь 1
    • m[0] получает назначенное ранее возвращенное (по m.size()) 1
  • Настоящий ответ?, который мне неизвестен ^^

4b9b3361

Ответ 1

Я считаю, что неопределенно, сохраняется ли 0 или 1 в m[0], но это не поведение undefined.

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

Назначение - это фактическое присвоение int, а не вызов функции с соответствующими точками последовательности, поскольку operator[] возвращает T&. Это короткое беспокойство, но это не изменение объекта, к которому обращаются в любом другом месте этого заявления, так что это тоже безопасно. Он получил доступ к operator[], конечно, там, где он инициализирован, но это происходит перед точкой последовательности при возврате из operator[], так что ОК. Если это не так, m[0] = 0; тоже будет undefined!

Однако порядок оценки операндов operator= не указан стандартом, поэтому фактический результат вызова size() может быть 0 или 1 в зависимости от того, какой порядок выполняется.

Однако было бы undefined поведение. Он не вызывает вызовы функций и поэтому не позволяет предотвратить доступ к size (по RHS) и изменен (на LHS) без промежуточной точки последовательности:

int values[1];
int size = 0;

(++size, values[0] = 0) = size;
/*     fake m[0]     */  /* fake m.size() */

Ответ 2

В этом выражении нет последовательность точек между вызовом operator [] и вызовом clear. Следовательно, поведение должно быть undefined.

Ответ 3

Он печатает 1 и не поднимает предупреждение (!) с помощью gcc. Он должен вызывать предупреждение, потому что это undefined.

Класс приоритета как operator[], так и operator. равен 2, тогда как класс приоритета operator= равен 16.
Это означает, что он четко определен, что m[0] и m.size() будут выполнены до назначения. Однако не определено, какой из них выполняется первым.

Ответ 4

Учитывая, что С++ 17 здесь в значительной степени, я думаю, стоит упомянуть, что этот код теперь демонстрирует хорошо определенное поведение в соответствии с новым стандартом. Для этого случая = является встроенным присваиванием целому числу:

[expr.ass]/1:

Оператор присваивания (=) и все операторы присваивания группа справа налево. Все требуют модификации lvalue как их левые операнд и возвращает lvalue, ссылаясь на левый операнд. Результат во всех случаях это бит-поле, если левый операнд является битовым полем. В целом случаев, присваивание упорядочивается после вычисления значения правый и левый операнды, а перед вычислением значения присваивание. Правильный операнд секвентирован перед левым операнд. Что касается вызова функции с неопределенной последовательностью, операция составного присвоения представляет собой единую оценку.

Что оставляет нас только с одним вариантом, а это № 2.