Почему происходит сбой следующего кода?

int main(int argc, const char * argv[]) {


std::list<int> aList={1,2,3,4,5};

std::list<int>::reverse_iterator i=aList.rbegin();
i++;
i++;

assert(*i==3);//assertion passes as expected


while (i!=aList.rbegin()) { //never becomes false
      aList.pop_back(); //segmentation fault

}
assert(*(aList.rbegin())==3);

return 0;
}

Я предполагаю, что rbegin в конечном итоге будет равен i и остановлю цикл; Однако не происходит.

Обратите внимание, что я сделал после обхода, все еще любопытно, что не так с приведенным выше кодом в первую очередь

size_t  differance =std::distance( aList.rbegin(),i);

while (differance >0) {
    aList.pop_back();
    differance--;
}
assert(*aList.rbegin()==3);
2
Mal Ma 23 Мар 2017 в 21:30

2 ответа

Лучший ответ

std::list::rbegin() возвращает итератор, который ссылается на дозорный конец -of-list узла, но разыменовывает к значению, сохраненному в предыдущем узле (5 в вашем случае). Это поведение применимо к любому обратному итератору std::list: узел, с которого вы получаете значение при разыменовании, обратный итератор - это узел перед узлом, на который фактически указывает итератор.

Визуализируйте это так, с точки зрения того, на какой элемент ссылаются итераторы:

rend() <-------- rbegin()
  |                 |
  1     2 3 4 5   (end)
  |                 |
begin() --------> end()

Это означает, что итератор, разыменовывающий значение 3, фактически ссылается на элемент со значением 4. Когда значение 4 удаляется из списка, значение итератора сохраняется в i становится недействительным, и в этот момент вы не можете рассуждать о его поведении. Вероятно, он будет (и должен быть) не равным любому другому итератору.

Вы можете убедиться в этом сами, выписав значение *(i.base()) при *i == 3. Вы увидите это *(i.base()) == 4.

Таким образом, ваша проблема не в том, что rbegin() итераторы «никогда не равны итератору, указывающему в список», ваша проблема в том, что вы удаляете элемент, на который внутренне указывал итератор, а затем пытаетесь сравнить этот теперь недействительный элемент итератор в rbegin().

Попробуйте использовать aList.erase() вместо вашего цикла. Поскольку вы хотите удалить элемент со значением 4 до конца массива, i.base() уже предоставляет вам итератор, который вы можете напрямую передать в aList.erase():

aList.erase(i.base(), aList.end());
0
cdhowie 23 Мар 2017 в 19:31

Похоже, у вас все это в обратном порядке, приращение обратного итератора перемещает его назад.

И pop_back() сделает недействительным итератор до последнего элемента, следовательно, это ошибка в вашем цикле. Вы должны сделать pop_front() и проверить (i !=rend())

0
P0W 23 Мар 2017 в 18:47