Постинкрементный итератор после разыменования — * iter ++. Как это оценивается?

Я не смог найти более подходящее название для этой проблемы, пожалуйста, обновите его, если необходимо, согласно приведенному ниже вопросу.

Рассмотрим итератор — iter, указывая на элементы в std::vector<int>, Я вставляю значение *iter в текущей позиции итератора, используя:

iter = target.insert(iter, *iter);

Я это понимаю insert вернет итератор во вновь вставленный элемент. Теперь я изменил вышеприведенное утверждение на:

iter = target.insert(iter, *iter++);

Я знал, что будет вести себя неловко, и это привело к Ошибка сегментации. Что я не могу понять, так это то, как оценивается вышеуказанное задание? Я имею в виду, какой элемент будет iter указать после этого назначения. Насколько я понимаю, так как я использовал пост-инкремент оператор, он должен вести себя так же, как и первый оператор, который я выведу из приведенного ниже примера назначения:

i = i++;

Поскольку вышеприведенное назначение не влияет на значение iТо же самое должно быть верно в случае *iter++,

Каково реальное поведение за сценой?


Это настоящий код:

std::vector<int>::iterator begin = target.begin();

while (begin != target.end()) {
if (*begin % 2 == 0) {
begin = target.erase(begin);
} else {
begin = target.insert(begin, *begin); // I changed this line
begin += 2;
}
}

По сути, приведенный выше код удаляет четный элемент из вектора и дублирует нечетный элемент.

Редактировать:

Хорошо, если я изменю вторую строку на ++beginкроме предыдущего изменения — работает так же, как и текущий код. Итак, я заменил две строки в else блок, с этими строками:

begin = target.insert(begin, *begin++);
++begin;

Таким образом, похоже, что он присваивает итератору одно прошлое, чем в предыдущем случае.

Итак, вот что я понял из этого поведения:

  • *begin++ первые разыменовывает begin чтобы получить значение в текущем местоположении.
  • begin постинкрементно
  • insert теперь вставляет разыменованное значение перед итератором после постинкремента. Таким образом, он не вставляет перед оригиналом beginскорее перед ++begin, И затем возвращает значение ++beginгде он вставлен.

Я правильно истолковал это?

3

Решение

Я не мог понять ваш вопрос, но ответить на понимание, которое вы перечислили: Ваше понимание может быть правильным на конкретном компиляторе / день / сборка. это неопределенные будете ли вы вставлять в begin или же begin + 1 (что затем приводит к значению, возвращенному из insert является одним из двух возможных значений), потому что компилятор может оценить аргументы insert в любом порядке это нравится. Вместо того, чтобы пытаться понять, что именно произойдет, разбейте код на соответствующие части, чтобы они четко поняли, что вы пытаетесь сделать, и позволили оптимизатору позаботиться о вас. Почти наверняка причина, по которой ядро ​​сбрасывается, заключается в том, что при увеличении на два вы пропускаете end и никогда не обнаружит, что вы прошли конец контейнера.

Я чувствую, что должен также указать, что «к счастью» есть точка последовательности после оценки аргументов функции, или begin = target.insert(begin, *begin++); было бы неопределенным поведением с двумя записями в begin и нет промежуточной точки последовательности (например, i = i++ это UB).

3

Другие решения

AFAIK Вы создаете target.insert (iter, * iter ++), который не является допустимым c ++, так как ведет к «неопределенному поведению». * iter ++ допустим и оценивается слева направо, но порядок, в котором оцениваются агрегаты вызова функции, не указан. Написание такого выражения является ошибкой программирования.

если быть точным, твой код

target.insert(iter, *iter++)

данные псевдонимы

std::vector<int>::iterator cur = iter;
std::vector<int>::iterator next = iter + 1;

можно оценить этими двумя способами

targets.insert(next, *cur);
++iter;

или же

targets.insert(cur, *cur);
++iter;

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

1

По вопросам рекламы [email protected]