4

После ответа this question продолжилось обсуждение того, был ли этот код неопределенным поведением или нет. Вот код:Является ли индексирование нового элемента карты и что-то, что читает ему, присвоенное ему неопределенное поведение или просто неуказанное?

std::map<string, size_t> word_count; 
word_count["a"] = word_count.count("a") == 0 ? 1 : 2; 

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

Там была короткая форма, которая пришла, а также:

(x = 0) = (x == 0) ? 1 : 2; //started as 
(x = 0) = (y == "a") ? 1 : 2; //changed to 

Я утверждал, что это было больше похоже на это:

(x = 0, x) = (x == 0) ? 1 : 2; //comma sequences x, like [] should 

В конце концов, я нашел пример, который, казалось, работа для меня:

i = (++i,i++,i); //well-defined per SO:Undefined Behaviour and Sequence Points 

Обратно к оригиналу, я разбил его на соответствующие вызовы функций, чтобы было легче следовать:

operator=(word_count.operator[]("a"), word_count.count("a") == 0 ? 1 : 2); 
^  inserts element^      ^reads same element 
    | 
assigns to element 

Если word_count["a"] не существует, было высказано мнение о том, что он будет назначен дважды без последовательности между ними. Я лично не видел, как это могло произойти, если две вещи, я думал, что было правдой на самом деле были:

  1. Когда сторона определена для оценки, вся сторона должна быть оценена, прежде чем другая сторона может начать.

  2. Конструкции, такие как word_count ["a"] = 1, демонстрируют хорошо определенное поведение даже в том случае, если элемент вставлен и затем назначен.

Являются ли эти два утверждения истинными? В конечном счете, это фактически неопределенное поведение, и если да, то почему второй оператор работает (если он это делает)? Если вторая ложь, я считаю, что все myMap[i]++; в мире будут плохо сформированы.

Полезные ссылки: Undefined behavior and sequence points

+0

Связанный с этим вопрос в контексте C: http://stackoverflow.com/questions/13935904/is-xyyx-undefined-or-unspecified-and-if-unspecified-what-can-it –

+0

@PascalCuoq, Спасибо, это кажется очень актуальным. Вопрос в том, сохраняет ли это значение для C++ (это почти наверняка делает) и распространяется ли это на создание нового элемента на карте. – chris

+0

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

ответ

5

Поведение неуказано, но не определено.

Обратите внимание, что в выражении:

word_count["a"] = word_count.count("a") == 0 ? 1 : 2; 
//   ^

Оператор присваивания отмечен ^ является встроенный оператора присваивания, потому что std::map «s operator [] возвращает size_t&.

в соответствии с пунктом 5.17/1 из C++ 11 стандарта на оператора присваивания встроенным (ы):

Оператор присваивания (=) и операторы присваивания соединение вся группа правой-to оставил. [..] Во всех случаях назначение упорядочивается после значения вычисления правого и левого операндов и перед вычислением значения выражения присваивания. Что касается вызова функции с неопределенной последовательностью, то операция составного присвоения равна для одной оценки.

Это означает, что в встроенном присваивании, такие как:

a = b 

Сначала операнды вычисляются (в произвольном порядке), то задание выполняется, и, наконец, вычисление значения целого выполняется выражение присваивания.

Учитывая исходное выражение:

word_count["a"] = word_count.count("a") == 0 ? 1 : 2; 
//   ^

Из пункта приведенного выше, ни в коем случае есть два unsequenced задания на тот же объект: назначение, отмеченные ^ всегда будет секвенировало после в присвоение выполнено operator [] (как часть оценки выражения левой стороны) в случае, если ключ "a" отсутствует на карте.

Однако выражение будет иметь другой результат, основанный на том, какая сторона вычисления оценивается первой. Таким образом, поведение неуказано, но не определено.

+0

Спасибо, ты не знаю, насколько это заставляет меня успокоиться после всего этого. – chris

+0

@chris: Рад, что это помогло. Секвенирование и UB по-прежнему меня путают время от времени, поэтому, хотя я нахожу аргумент, который я здесь приводил достаточно убедительно, я никогда не уверен на 100%. Надеюсь, у меня все получилось. –

+0

@chris: Я снова впал в сомнение: 1.9/15 "* Если побочный эффект на скалярном объекте не влияет на какой-либо другой побочный эффект на тот же скалярный объект ** или значение вычисление с использованием значения одного и того же скалярного объекта **, поведение не определено. * «Здесь я не уверен, что выражение левой стороны содержит побочный эффект, который модифицирует скалярное значение, которое считывается при оценке правой стороны выражение. –

2

Это не определено, но не определено.

word_count.operator[]("a") и word_count.count("a") являются функциональными вызовами. Выполнение функций гарантируется стандартом, чтобы не чередовать - либо сначала полностью упорядочивается до второго, либо наоборот.

Конкретное определение может варьироваться в зависимости от стандартного, в 11 соответствующем пункте C++ в 1.9/15:

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

9) Иными словами, выполнение функций не чередуется друг с другом.

неопределенно секвенировали определен в 1.9/13:

Оценки А и В неопределенно секвенировали, когда либо А секвенированы перед В или В секвенируют, прежде чем A, но это не определено который.

Например, оценка:

word_count["a"] = word_count.count("a"); 

состоит из трех частей:

  1. исполнение word_count.operator[]("a")
  2. исполнения word_count.count("a")
  3. Назначение

Let < среднее значение «секвенировано до». Цитированная часть стандарта гарантирует, что либо 1 < 2, либо 2 < 1. Часть, указанная в ответе @Andy Prowl, также показывает, что и 1 < 3, и 2 < 3. Таким образом, есть только два варианта:

  • 1 < 2 < 3
  • 2 < 1 < 3

В обоих случаях все полностью упорядоченным и нет никаких шансов на УБ.

+1

Извините, я отредактировал неправильный ответ! (хотел изменить мой) –

+0

@ AndyProwl, Lol! Я никогда не видел этого раньше :) – chris

+1

@chris: [Это случается!] (Http://stackoverflow.com/questions/15730484/arrange-data-in-vector-issue#comment22348453_15730503) :) –

 Смежные вопросы

  • Нет связанных вопросов^_^