Вы могли бы хотеть объяснить, что Вы действительно хотите сделать.
, Если внешнее for
циклы делают только управление количеством, то Вашим вложенным for
циклы является просто более сложный способ выполнить итерации количеством, которое могло быть обработано синглом for
цикл.
, Например:
for (x = 0; x < 10; ++x) {
for (y = 0; y < 5; ++y) {
for (z = 0; z < 20; ++z) {
DoSomething();
}
}
}
эквивалентно:
for (x = 0; x < 10*5*20; ++x) {
DoSomething();
}
Отредактировано с более тщательной формулировкой
да, изменение размера вектора может сделать недействительными все итераторы, указывающие на вектор.
Вектор реализуется путем внутреннего выделения массива, в котором хранятся данные. Когда вектор растет, в этом массиве может закончиться место, и когда это происходит, вектор выделяет новый, более крупный массив, копирует данные в него, а затем удаляет старый массив.
Итак, ваши старые итераторы, которые указывают на старую память, больше не действительны.
Однако если вектор изменить размер вниз (например, с помощью pop_back ()
), то используется тот же массив. Размер массива никогда не уменьшается автоматически.
Один из способов избежать этого перераспределения (и недействительности указателя) - сначала вызвать vector :: reserve ()
, чтобы выделить достаточно места, чтобы в этом копировании не было необходимости . В вашем случае, если вы вызвали a.reserve (3)
перед первой операцией push_back ()
, тогда внутренний массив будет достаточно большим, чтобы push_back
могут быть выполнены без перераспределения массива, поэтому ваши итераторы останутся действительными.
Итераторы вектора становятся недействительными только тогда, когда вектор выполняет перераспределение.
Вызов push_back (4)
заставляет вектор выделить новый блок памяти - это то, что приводит к тому, что ваш итератор становится недействительным. Когда вы также используете push_back (3)
, перераспределение не выполняется для push_back (4)
, поэтому итератор остается действующим.
Да, любое действие, которое может изменить размер вектора, может сделать итераторы недействительными.
Изменить: это включает операции (например, erase ()
, изменение размера ()
), уменьшающие размер контейнера. erase ()
не делает недействительными все итераторы, но делает недействительными все итераторы, ссылающиеся на любую точку после стертого элемента (ов). resize ()
определяется в терминах insert ()
и erase ()
, поэтому имеет тот же потенциал.
Для справки в будущем, все виды лакомых кусочков STL, подобные этому, находятся на веб-сайте SGI: http://www.sgi.com/tech/stl/Vector.html
Если вам нужно, чтобы итераторы оставались действующими после добавления или удаления коллекции, обратите внимание на другой тип коллекции, например, список.
Лучше всего, однако, выделить из матрицы требуемые функции из коллекции (произвольный доступ и т. д.), затем выберите правильный контейнер.
См. статью в Википедии о контейнерах Standard_Template_Library для начала. Если у вас есть деньги, я настоятельно рекомендую «Эффективный STL: 50 конкретных способов улучшить использование стандартной библиотеки шаблонов» Скотта Мейера.
Приносим извинения за отсутствие ссылок поддержки, я здесь новичок и у меня нет репутации, чтобы публиковать это более чем с одной.
Правила аннулирования итератора специфичны для контейнера.
Теперь аннулирование может иметь два значения с вектором:
Как видите, второй гораздо более строгий:
std::vector<int> myVector;
myVector.push_back(0);
myVector.push_back(1);
std::vector<int>::iterator it = myVector.begin(); // it points to 0
myVector.erase(it); // it points to 1
myVector.erase(it); // it == myVector.end()
В этом случае он «действителен», поскольку он всегда находится во включительном range [начало, конец], поэтому его можно безопасно использовать для любой операции с myVector. С другой стороны, выражение (* it) постоянно меняется: сначала оно возвращает 0, затем 1, затем имеет неопределенное поведение ...
В общем, люди скорее будут говорить о втором требовании, а признание итератора недействительным просто означает что (* it) может не дать того же результата, что и раньше.
Теперь, когда это сказано, есть несколько способов сделать недействительным итератор вектора (фактически, это менее стабильная структура STL).
Во время добавления элементов:
insert
. Вставка элемента делает недействительными итераторы, указывающие на эту текущую позицию и все последующие, поскольку элементы сдвигаются на один шаг в сторону конца вектора. Во время удаления элементов:
(1) Внутренняя структура std :: vector - это массив T, это связано с совместимостью с C-программами (с использованием & myVector.front () в качестве адреса массива) и тем, что он гарантирует непрерывность и минимальные накладные расходы на пространство (т. е. количество пространства, занимаемого собственными данными вектора, по сравнению с количеством пространства, занимаемого объектом)
В любой момент вы можете узнать, сколько объектов может вместить вектор, используя метод .capacity ().
Когда вы хотите вставить объект, а вектор не имеет необходимой емкости , запускается вызов метода .reserve (size_t). Этот метод, который будет выделять столько памяти, сколько необходимо (минимум в зависимости от библиотеки), и копировать элементы myVector. Затем операция подкачки обменивает буферы из myVector и этой копии, и, таким образом, myVector теперь хранит буфер с минимально необходимым объемом памяти. В конце операции временное устройство уничтожается, а хранимая в нем память освобождается.