неправильный вывод при назначении вектора?

Фрагмент кода ниже взят из блога Херба Саттера здесь

g++ выводит 10. MSVC также выводит 10. Вывод может отличаться на разных компиляторах.

Я не понимаю, как увеличивается переменная i. Может ли кто-нибудь объяснить мне, почему вывод 10, действительно ли 10 правильный вывод?

#include <iostream>
#include <vector>
#include <string>

int main()
{    
    std::vector<int> v = { 0, 0 };
    int i = 0;
    v[i++] = i++;
    std::cout << v[0] << v[1] << std::endl;
}

person user1    schedule 07.12.2015    source источник


Ответы (2)


ОТРЕДАКТИРОВАНО

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

Прежде всего, давайте констатируем факт:

  • i++ увеличит значение i, но вернет исходное значение, которое я хранил до увеличения.

из В чем разница между ++i и i++? .

Теперь линия

v[i++] = i++;

оценивает в вашем случае в порядке "LHS" -> "RHS" -> назначение:

  • LHS, v[i++]: i увеличивается до 1, а i++ возвращает 0 до v[i++].
  • RHS, i++: i теперь имеет значение 1, но увеличивается до 2, однако i++ из RHS возвращает 1.
  • Присваивание: Из приведенного выше присваивание получается: v[0] = 1 (после чего i имеет значение 2).

Следовательно, печать v[0] и v[1] будет оцениваться как 1 (обновленное значение) и 0 (как инициализированное) соответственно.

person dfrib    schedule 07.12.2015
comment
Очень хороший подход к простому объяснению того, что происходит в конкретном случае, я вернул свой dv! недурно. - person g24l; 07.12.2015
comment
Спасибо! Я надеюсь, что два отрицательных голоса в вашем ответе также пересмотрят свое мнение после вашего редактирования, я думаю, что это также актуальный ответ. - person dfrib; 07.12.2015
comment
ну они были правы на dv в начале, мне было не совсем понятно, о чем спрашивали! - person g24l; 07.12.2015

Это проблема порядка выполнения, и она не определена из-за С++ 11:

5.17 Операторы присваивания и составные операторы присваивания

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

Проще говоря, модификация левого аргумента выполняется после вычисления значения, но не побочных эффектов вычисления с обеих сторон и до возврата ссылки на объект.

Итак, действия, которые необходимо предпринять,

A. оценить левую часть (возвращаемое значение выражения i++ = 0)

B. вернуть ссылку на объект (вернуть ссылку на объект выражения v[i++])

C. вычислить побочные эффекты для левой стороны, т.е. i-> 1

D. вычислить побочные эффекты для правой стороны, т.е. i-> 2

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

person g24l    schedule 07.12.2015
comment
Просто дв, но без причины... Может стратегия?! - person g24l; 21.12.2015