поведение --it и it— в [дубликате]

0

Каково объяснение поведения it++ и ++it в контексте вызова функции --and более конкретно, для функции iter_swap? Это смущает меня, что вызов 2 и вызов 4 в приведенном ниже коде появляются для замены элементов, тогда как вызов 3 и вызов 5 не могут заменить элементы. Однако я ожидал противоположного результата, но предполагал, что одна из записей параметров функции будет выполняться перед другой. Глядя на результат, похоже, это не так.

Итак, из любопытства, определяется ли это поведение? Как я могу понять, в каком порядке выполняются действия? Благодарю!

#include <iostream>
#include <vector>
#include <algorithm>
int main(void) {
    vector<int> a;
    a.push_back(1);
    a.push_back(2);

    vector<int>::iterator it_a, it_b;
    it_a = a.begin();
    it_b = it_a + 1;

    cout << *it_a << " " << *it_b << endl;
    // call 1
    iter_swap(it_a, it_b);
    cout << *it_a << " " << *it_b << endl;
    // call 2
    iter_swap(it_a, it_a++);
    cout << *--it_a << " " << *it_b << endl;
    // call 3
    iter_swap(it_a, ++it_a);
    cout << *--it_a << " " << *it_b << endl;
    // call 4
    iter_swap(it_a++, it_a);
    cout << *--it_a << " " << *it_b << endl;
    // call 5
    iter_swap(++it_a, it_a);
    cout << *--it_a << " " << *it_b << endl;

    return 0;
}

выходы:

1 2
2 1
1 2
1 2
2 1
2 1
  • 0
    Порядок оценки аргументов не указан, и в списке аргументов нет точки последовательности, поэтому вызовы вашей функции приводят к неопределенному поведению .
Теги:
iterator
pre-increment
post-increment

1 ответ

2
Лучший ответ

Большинство из этих примеров не имеют определенного поведения (единственным вызовом является вызов 1). Оценка аргументов функции не имеет никакого значения, что означает, что их порядок оценки неуточнен, поэтому вопрос о том, был ли побочный эффект operator++ другим аргументом к моменту operator++ функции, не определен. С другим компилятором вы могли бы получить другой результат, и оба они были бы совершенно стандартными.

Добавление: Некоторое объяснение семантики в порядке, я считаю.

До С++ 11 я бы говорил о точках последовательности здесь, но стандартный язык изменился, чтобы быть яснее, не меняя очень многого. Поэтому вместо этого я расскажу о последовательности операций.

Как правило, операции на С++ 11 частично упорядочены по времени. Иными словами, две операции (пусть их называют O и P) могут быть секвенированы, так что O секвенируется до P, что O секвенируется после P или что O и P неопределенно секвенированы или что O и P не подвержены влиянию.

Первые два являются простыми: если O секвенирован до P, все его эффекты должны были произойти к моменту времени P оценивается, если O секвенирован после P, все эффекты P появлялись, когда O приближается.

Что касается двух других: если O и P неопределенно секвенированы, то либо все эффекты O отображаются до P, либо все эффекты P появляются до O. Если они не подвержены влиянию, это отличная свобода для всех: некоторые эффекты O могут появиться перед некоторыми эффектами P, и в то же время некоторые эффекты P могут появиться до появления всех эффектов O - фактически, оценка O и P могут перекрываться.

Это следует рассматривать в контексте оптимизации: оптимизация компиляторов позволяет переупорядочить код, чтобы он работал быстрее. Частичные спецификации с точки зрения последовательности позволяют им делать гораздо больше этого - возможно, O имеет промежуточный результат, полезный для оценки P, такого рода вещи. Если вы считаете, например, большое арифметическое выражение, нетрудно понять, насколько слабая последовательность может помочь в векторизации и при наличии ограниченного числа регистров.

Итак, где ваши примеры падают?

В разделе 1.4 (15) С++ 11 упоминается, что "вычисления значений и побочные эффекты, связанные с разными выражениями аргументов, не имеют никакого значения". Таким образом, вы находитесь в глубоком конце здесь, плавая с драконами.

  • 0
    Что еще хуже, у нас не только неопределенное поведение, но и неопределенное поведение. Помните, что вектор-итератор может быть простым указателем.
Сообщество Overcoder
Наверх
Меню