Нужно удалить элемент из std::listпо итератору. Стандарт С++11 и выше не используется. То есть имеется только функция iterator std::list::erase( iterator first, iterator last );
Если я сделаю так, то элемент не удалиться:
void func(std::list<int>& l, std::list<int>::iterator it)
{
l.erase(it, ++it);
}
А если так, то все работает:
void func(std::list<int>& l, std::list<int>::iterator it)
{
std::list<int>::iterator it2 = it;
std::advance(it2, 1);
l.erase(it, it2);
}
Почему? Ведь в erase в обоих случаях передаются одинаковые итераторы. Есть ли какой способ удалить один элемент из списка без лишних действий?
Вы столкнулись с неопределённым поведением.
Дело в том, что компилятор имеет право вычислять значения аргументов функции в любом порядке. Так что в первом случае он может сначала вычислить и подставить значение второго аргумента (++it), и только потом — первого (it).
Во втором же случае значение it2 вычисляется гарантировано до его использования в строке l.erase(it, it2); благодаря (грубо говоря) наличию точки с запятой.
Всё это является следствием работы механизма точек следования. Подробнее о нём можно почитать, например, в статье «Точки следования (sequence points)» в блоге «Алёна C++».
Порядок вычисления и передачи аргументов в функции не определен. Т.е. компилятор может, например, сначала вычислить ++i, а потом передавать значение.
Например,
#include <iostream>
#include <iomanip>
using namespace std;
void f(int a, int b)
{
cout << a << " " << b << endl;
}
int main(int argc, const char * argv[])
{
int i = 3;
f(i,++i);
}
здесь, при том, что вы ожидаете 3 4, реально может быть 4 4 - и не только может, но и VC++, и GCC именно такой результат и дают.
P.S. См. понятие "точка следования".
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости