Ответ 1
В ситуациях, когда итератор является классом, поведение хорошо определено во всех версиях стандарта, предполагая, что it++
указывает на допустимое местоположение внутри его контейнера (что в вашем примере оно).
С++ переводит *it++
в эту последовательность из двух вызовов функций:
it.operator++(0).operator*();
Функциональные вызовы вводят последовательность, поэтому все побочные эффекты фактического ++
, вызываемого внутри operator++
в примитиве, используемом как реализация итератора (возможно, необработанный указатель), должны быть завершены до выхода функции.
Однако итераторы не должны быть классами: они также могут быть указателями:
struct foo {
typedef int* iterator;
iterator begin() { return data; }
private:
int data[10];
};
Код выглядит одинаково, и он продолжает компилироваться, но теперь поведение undefined:
foo f;
auto it = f.begin();
*it = *it++; // <<== This is UB
Вы можете предотвратить это, вызвав ++
как функцию-член:
std::vector<int> v = {1, 2};
auto it = v.begin();
*it = *it.operator++(0);
Когда итератор на самом деле является указателем, этот код не будет компилироваться, а не вызывает поведение undefined.