2015-11-23 5 views
5
#include <iostream> 
#include <map> 

int main(int argc, char** argv) 
{ 
    std::map<int, int> map; 
    map.emplace(1, 1); 
    auto reverse_iter = map.rbegin(); 
    std::cout << reverse_iter->first << ", " << reverse_iter->second << std::endl; 
    map.emplace(2, 2); 
    std::cout << reverse_iter->first << ", " << reverse_iter->second << std::endl; 

    return 0; 
} 

Это печатает:Это правильное поведение? станд :: Карта итератора недействительности

1, 1 
2, 2 

Является ли это действительно то, что должно произойти, в соответствии со стандартом? Я не трогаю reverse_iter, но значение, на которое оно указывает, меняется. Я думал, что итераторы на std :: map должны быть в безопасности от вставки. Тем не менее, похоже, что решение reverse_iter не должно указывать на ценность, о которой я сказал, а скорее «что бы ни случилось в конце карты на данный момент времени».

Обновление: дальнейшая информация, в случае, если это имеет значение: похоже, что это не происходит с итераторами вперед (в любой ситуации, которую я могу найти), а моя версия gcc 5.1.1-4.

+0

Будучи «аннулированных» и указывая на новые данные не то же самое, они? Это действительный указатель на последнюю пару в вашем контейнере. Эта пара просто изменилась. – tadman

+0

Не происходит с итераторами вперед. Замените rbegin на начало и замените (2, 2) на (0, 0). И опять же, соответствует ли это стандартам? Потому что это действительно штопает неожиданно, это точно. – KarenRei

+0

Правильно, первое, что вы положили на карту, не изменится. Однако последнее, что вы сделали, будет. – tadman

ответ

3

Как указано здесь http://en.cppreference.com/w/cpp/container/map/rbegin

реверсивный итератор хранит итератор к следующему элементу, чем тот, что на самом деле относится к

побочный эффект будет то, что если вставить что-то до этого итератора (()) вы увидите это новое значение, когда вы разыщите этот обратный итератор. Я не думаю, что обратный итератор недействителен в этом случае.

+0

Итак, в принципе, он разбит дизайном? : Þ Изменения в чем-то рядом с используемым итератором могут изменить итератор, который вы используете? Отлично ...: Þ Но, если это стандарт, ничего не могу сделать. – KarenRei

+0

Я думаю, вы вводите в заблуждение «действительный» и «последовательный». Недопустимый - это очень конкретная вещь, это означает, что итератор не должен использоваться, так как это приведет к неопределенному поведению. Ваши ожидания, что то, на что указывает итератор, не изменится после манипулирования картой, не выполняются, но это не проблема со стандартом. – tadman

+0

Учитывая, что вся цель итераторов заключается в замене указателей и индексирования, я бы сказал, что стандарт, который их изменяет, когда вы изменяете то, на что они не указывают, очень сломан. Я также сказал бы, что поведение, несовместимое между итераторами вперед и назад, также очень нарушено. Но что есть, то есть. – KarenRei

4

В соответствии со стандартом C++ (23.2.4 Ассоциативные контейнеры)

9 Вставка и устанавливать элементы не должны влиять на действительность итераторы и ссылки на контейнер, а члены стирани должны только Invalidate итераторы и ссылки на стертые элементы.

С другой стороны (24.5.1) Обратные итераторы

1 Класс шаблона reverse_iterator является итератора адаптер, который перебирает от конца последовательности, определенной с помощью лежащих в его основе итератора к началу эта последовательность.

Хотя в последней цитате сказано о классе std::reverse_iterator то же самое справедливо и для итераторов с обратным итератором стандартных контейнеров.

В соответствии с таблицей 97 - Обратимые требования контейнеров

rbegin() соответствует reverse_iterator(end())

Таким образом, в вашем примере обратный итератор все еще соответствует end(). `

1

map.rbegin() возвращает итератор, равный std::reverse_iterator(map.end());

Проблема возникает, когда вы разыменовывать обратный итератор. При разыменовании reverse_iterator значение, которое вы действительно получаете, - от итератора до того, как оно хранится внутри reverse_iterator. Это может показаться странным, но по уважительным причинам, и это неизбежно.Это так, чтобы упорядочить элемент конца диапазона: Итератор, указывающий на элемент конца в конце, при обратном, указывает на последний элемент (а не мимо него) диапазон (это будет первый элемент в обратном диапазоне). И если итератор первого элемента в диапазоне обращается вспять, обратный итератор указывает на элемент перед первым элементом (это будет элемент конца прошлого диапазона).

То есть, в вашем случае, когда разыменования reverse_iter эквивалентен делать:

*(--map.end()); 

Следовательно, после второго emplace последнего элемента карты изменился и разыменование (--map.end()) (т.е., ваш reverse_iter) вас получить новый последний элемент на карте.

0
std::map<int, int> map2; 
map2.emplace(2, 2); 
auto fiter = map2.begin(); 
std::cout << fiter->first << ", " << fiter->second << std::endl; 
map2.emplace(1, 1); 
std::cout << fiter->first << ", " << fiter->second << std::endl; 
fiter = map2.begin(); 
std::cout << fiter->first << ", " << fiter->second << std::endl; 

печатает

2, 2 
2, 2 
1, 1