Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 [ 35 ] 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239

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

игх.

\У v

Рис. 5.7, принцип действия алгоритма remove()

Однако алгоритм возвращает итератор, указывающий на новый конец коллекции. Это значение позволяет прочитать полученный интервал, уменьшить размер коллекции или узнать количество удаленных элементов. Рассмотрим слегка измененную версию примера:

stl/remove?.срр #1nc"lude <1ostream> #1nclude <l1st> linclude <algorithm> using namespace std:

int mainO {

I1st<1nt> coll:

Вставка элементов со значениями от 6 до 1 и от 1 до 6 for (1nt i=l; 1<=б; ++i) {

coll.push frontCi):

coll.push back(i);

Вывод всех элементов коллекции copy (coll.beginO. coll.endO.

ostream i terator<i nt>(cout." cout « endl;

Удаление всех элементов со значением 3 - сохранение нового конца коллекции list<1nt>: :iterator end = remove (coll.beginO. coll.endO

Вывод элементов полученной коллекции copy (coll .beginO . end.

ostream 1terator<int>(cout." ")): cout « endl:



Вывод количества "удаленных" злеиентов cout « "number of removed elements: " « dIstanceCend.coll .endO) « endl:

Стирание "удаленных" элементов coll.erase (end, coll.endO);

Вывод всех злементов модифицированной коллекции сору (coll.beginO. coll.endO.

ostream iterator<1nt>(cout." ")): cout « endl;

В новой версии программы значение, возвращаемое алгоритмом remove(), присваивается итератору end:

list<lnt>: ;lterator end = remove (coll.beginO. coll.endO.

Итератор end определяет «логический» конец модифицированной коллекции после «удаления» элементов. Полученное эначение определяет конечную границу интервала при последующих операциях:

сору (coll.beginO, end,

ostream iterator<int>(cout." "));

Другой способ основан на обработке количества «удаленных» элементов, вычисляемого как расстояние между «логическим» и «физическим» концами коллекции;

cout « "number of removed elements; " « d1stance(end,coll .endO) « endl;

В этом фрагменте используется специальная вспомогательная функщ-ш distance(), возвращающая расстояние между двумя итераторами. При работе с итераторами произвольного доступа расстояние вычисляется простым вычитанием оператором -, однако в нашем примере используется список, который поддерживает только двунаправленные итераторы. Дополнительная информация о функции distanceO приведена на с. 267.

Чтобы «удаленные» элементы были действительно удалены из коллекции, следует вызвать соответствующую функцию контейнера. Для таких целей контейнеры поддерживают функцию erase(), которая удаляет все элементы из интервала, определяемого переданными аргументами:

coll.erase (end. coll.endO):

Результат работы программы:

654321123456 6542112456

Определение distance() было изменено, поэтому в старых версиях STL необходимо включать файл distance.hpp (см. с. 268).



number of removed elements: 2 654211245656

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

coll .erase (reinove(coll .beginO .coll ,end(). 3).

coll.endO):

Почему сами алгоритмы не вызывают функцию erase()? Ответ на этот вопрос снова напоминает о том, что гибкость STL не дается даром. STL отделяет структуры данных от алгоритмов, используя итераторы в качестве интерфейсов. Но как отмечалось выше, итератор является абстракцией для представления позиции в контейнере. В общем случае итератор просто не знает свой контейнер. Таким образом, алгоритм, работающий с элементами контейнера через итератор, не может вызывать функции контейнера.

Подобная архитектура имеет важные последствия, поскольку благодаря ей алгоритмы работают с абстрактными интервалами, а не только со «всеми элементами контейнера». Например, интервал может состоять из подмножества элементов коллекции. Более того, некоторые контейнеры (например, обычные массивы) не поддерживают функцию erase(). Следовательно, стремление сохранить максимальную гибкость алгоритмов не позволяет требовать, чтобы итераторы располагали информацией о своих контейнерах.

Наконец, необходимость в уничтожении «удаленных» элементов возникает не так уж часто. Часто проще использовать новый «логический» конец контейнера вместо «физического», в частности, при последующем вызове всех алгоритмов.

Модифицирующие алгоритмы и ассоциативные контейнеры

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

К сожалению, в некоторых системах обработка ошибок реализована крайне плохо. Вы понимаете, что в программе что-то явно не так, но причины происходящего остаются неизвестными. Некоторые компиляторы даже не отображают фрагмент исходного текста, а котором обнаружена ошибка. Вероятно, в будущем ситуация изменится.



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 [ 35 ] 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239