Что означает недействительность контейнера в C ++? - PullRequest
2 голосов
/ 27 июля 2010

Сегодня я узнал о термине invalidation в контексте контейнеров C ++.Может кто-нибудь объяснить, что это значит?

Похоже, вам не разрешается каким-либо образом изменять элементы контейнера при циклическом перемещении по контейнеру.Но каким именно образом?

Пожалуйста, помогите мне разобраться в этой теме.

Спасибо, Boda Cydo.

Ответы [ 4 ]

5 голосов
/ 27 июля 2010

Контейнеры не становятся недействительными - итераторы , ссылающиеся на элементы в контейнерах, становятся недействительными.

Итератор - это дескриптор определенного элемента в контейнере.Итератор действителен до тех пор, пока этот элемент остается внутри контейнера, и контейнер не перестраивается внутри себя.Итератор становится недействительным, когда происходит одна из этих двух вещей, поскольку после слов итератор больше не является допустимым в качестве дескриптора в контейнере.

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

std::set<int> s;

s.insert(4);
s.insert(2);

std::set<int>::iterator itr = s.find(4); // itr is a handle to 4

std::cout << *itr << std::endl; // prints 4

s.erase(4); // removes 4 from collection, invalidates itr

std::cout << *itr << std::endl; // undefined behavior

Более тонкий способ аннулировать итератор - заставить контейнер внутренне переставить себя (например, перераспределить внутреннее хранилище).Это может быть сделано, например, путем расширения определенных типов контейнеров:

std::vector<int> v;

v.push_back(4);
v.push_back(2);

std::vector<int>::iterator itr = v.begin(); // itr is a handle to 4

std::cout << *itr << std::endl; // prints 4

v.push_back(12); // MIGHT invalidate itr, if v expands its internal allocation

В некоторых контейнерах это можно предотвратить, предварительно зарезервировав пространство:

std::vector<int> v;

v.reserve(3); // Pre-allocate 3 elements

v.push_back(4);
v.push_back(2);

std::vector<int>::iterator itr = v.begin(); // itr is a handle to 4

std::cout << *itr << std::endl; // prints 4

v.push_back(12); // WILL NOT invalidate itr, since it will never cause v to expand

Документациядля каждого контейнера STL следует описать, при каких обстоятельствах аннулирование итератора произойдет или может произойти.

1 голос
/ 27 июля 2010

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

Например: vector итераторы становятся недействительными при размере контейнераизменения.list итераторы становятся недействительными при удалении базовых данных.

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

0 голосов
/ 27 июля 2010

Я думаю, что это все об аннулировании итератора.Там несколько примеров:

std::vector<int> v1(10);
std::vector<int> v2(11);
//1
for (std::vector<int>::iterator it = v1.begin(); it != v2.end(); ++it);
//2
for (std::vector<int>::iterator it = v1.begin(); it != v1.end(); ++it)
{
    v1.erase(it);
}
0 голосов
/ 27 июля 2010

Если у вас есть массив (или список) объектов, и зацикливаясь на них, вы удалили некоторые элементы - тогда простой индекс в массиве может быть недействительным, но итераторы все равно будут.

...