Я не смог найти более подходящее название для этой проблемы, пожалуйста, обновите его, если необходимо, согласно приведенному ниже вопросу.
Рассмотрим итератор — 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
где он вставлен.Я правильно истолковал это?
Я не мог понять ваш вопрос, но ответить на понимание, которое вы перечислили: Ваше понимание может быть правильным на конкретном компиляторе / день / сборка. это неопределенные будете ли вы вставлять в begin
или же begin + 1
(что затем приводит к значению, возвращенному из insert
является одним из двух возможных значений), потому что компилятор может оценить аргументы insert
в любом порядке это нравится. Вместо того, чтобы пытаться понять, что именно произойдет, разбейте код на соответствующие части, чтобы они четко поняли, что вы пытаетесь сделать, и позволили оптимизатору позаботиться о вас. Почти наверняка причина, по которой ядро сбрасывается, заключается в том, что при увеличении на два вы пропускаете end
и никогда не обнаружит, что вы прошли конец контейнера.
Я чувствую, что должен также указать, что «к счастью» есть точка последовательности после оценки аргументов функции, или begin = target.insert(begin, *begin++);
было бы неопределенным поведением с двумя записями в begin
и нет промежуточной точки последовательности (например, i = i++
это UB).
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;
точная версия зависит от компилятора, ОС, другого кода и т. д. и обычно не указывается.