Анимация
JavaScript
|
Главная Библионтека дотпратить копирование, используя контейнер со ссылочной семантикой. За подробностями обращайтесь на с. 226. О Требуется возмоэююсть присваивания элемента оператором присваивания. Контейнеры и алгоритмы используют оператор присваивания для замены старых элементов новыми. О Требуется возможность уничтожения элемента деструктором. Контейнеры уничтожают свои внутренние копии элементов при удалении этих элементов из контейнера. Следовательно, деструктор не должен быть закрытым (private). Кроме того, как обычно в С++, деструктор не должен инициировать исключения, иначе возможны абсолютно непредсказуемые последствия. Эти три операции - копирование, присваивание, уничтожение - автоматически генерируются для любого класса. Следовательно, любой класс автоматически удовлетворяет требованиям, если для него не были определены специальные версии этих операций или их нормальная работа не нарушается другими членами класса. Кроме того, к элементам могут предъявляться дополнительные требования О Для некоторых функций классов последовательных контейнеров требуется конструктор по умолчанию. Например, можно создать непустой контейнер или увеличить количество элементов без указания значений новых элементов. Такие элементы создаются вызовом конструктора по умолчанию для соответствующего типа. О Для некоторых операций требуется определить проверку па равенство оператором ==. Такая необходимость особенно часто возникает при поиске. О Для ассоциативных контейнеров требуется, чтобы элементы поддерживали критерий сортировки. По умолчанию используется оператор <, вызываемый объектом функции iesso. Семантика значений и ссылочная семантика Все контейнеры создают внутренние копии своих элементов и возвращают эти копии. Следовательно, элементы контейнера равны, но не идентичны объектам, заносимым в контейнер. При модификации объектов, являющихся элементами К01ггейиера, вы модифицируете копию, а ие исходный объект. Копирование значений означает, что контейнеры STL поддерживают семантику значений. Они содержат значения вставляемых объектов, а не сами объекты. Но на практике также возникает необходимость в ссылочной семантике, при которой контейнеры содержат ссылки на объекты, являющиеся их элементами. В некоторых старых системах С++ приходится обеспечивать выполнеше этих дополнительных требований, даже если они ие используются в программе. Например, некоторые реализации vector требуют обязательного наличия деструктора по умолчанию для элементов. В других реализациях всегда должен присутствовать оператор ciJasEie-ння. В соответствии со стандартом эти требования незаконны; скорее всего, в будущем подобные ограничения будут устранены. Реализация ссылочной семантики с применением указателей хорошо знакома программистам С. В языке С аргументы функций передаются только по значению, поэтому для передачи по ссылке приходится использовать указатели. Принятый D STL подход, то есть поддержка только семантики значений, имеет свои положительные и отрицательные стороны. К достоинствам такого подхода относятся: О простота копирования элементов; О при использовании ссылок часто возникают ошибки (программист должен следить за тем, чтобы ссылки не относились к несуществующим объектам, кроме того, необходимо предусмотреть обработку возможных циклических ссылок). Недостатки: О при отказе от ссылочной семантики копирование элементов может выполняться неэффективно или становится невозможным; О невозможность одновременного присутствия объектов в нескольких контейнерах. На практике нужны оба подхода: копии, независимые от исходных данных (семантика значений), и копии, ссылающиеся на исходные данные и изменяющиеся вместе с ними (ссылочная семантика). К сожалению, стандартная библиотека С++ не поддерживает ссылочную семаитику. Впрочем, ее можно реализовать в контексте семантики значений. Наиболее очевидная реализация ссылочной семантики основана на использовании указателей как элементов контейнеров*. Тем не менее обычным указателям присущи хорошо известные недостатки. Например, объект, на который ссылается указатель, оказывается несуществующим, или операция сравнения работает не так, как предполагалось, потому что вместо объектов сравниваются указатели на них. Следовательно, при использовании обычных указателей в элементах контейнеров нужно действовать очень осторожно. Более разумное решение основано на применении умных указателей - объектов, поддерживающих интерфейс указателей, но выполняющих дополнительную внутреннюю проверку или другие операции. Но здесь возникает важный вопрос: насколько умными должны быть эти указатели? В стандартную библиотеку С++ входит класс умного указателя auto ptr (см. с. 54), который на первый взгляд мог бы пригодиться. К сожалению, этот класс не подходит, поскольку не удовлетворяет одному из основных требований к элементам контейнеров, а именно: после копирования или присваивания объектов класса auto ptr оригинал и копия не эквивалентны. Исходный объект auto ptr изменяется, нотому что значение передается, а не копируется (см. с. 59 и 62). На практике это означает, что сортировка и даже простой вывод элементов контейнера может привести к их уничтожению. Следовательно, объекты auto ptr пе должны использоваться как элементы контейнеров (в системе С++, соответствующей стандарту, такие попытки приводят к ошибкам компиляции). Дополнительная информация приведена на с. 59. Чтобы реализовать ссылочную семантику для контейнеров STL, вам придется написать собственны!! класс умного указателя. Но будьте внимательны: исноль- зование умного указателя с подсчетом ссылок (умного указателя, который автоматически уничтожает связанный объект при уничтожении последней ссылки на него) вызовет немало проблем. Например, при прямом доступе к элементам возможна модификация их значений, пока они находятся в контейнере. В ассоциативном контейнере это приведет к нарушению порядка следования элементов, а это недопустимо. На с. 226 приведена дополнительная информация о контейнерах со ссылочной семантикой и продемонстрирован один из возможных способов реализации ссылочной семантики для контейнеров STL на базе умных указателей с подсчетом ссылок. Ошибки и исключения внутри STL Ошибки случаются, хотим мы того или нет. Они могут быть обусловлены как действиями программы (а точнее, программиста), так и контекстом или рабочей средой программы (например, нехваткой памяти). Обе разновидности ошибок обрабатываются при помощи исключений (начальные сведения об исключениях приводятся на с. 31). Данный раздел посвящен принципам обработки ошибок и исключений в STL. Обработка ошибок при проектировании STL главным приоритетом была максимальная произ-водигельность, а не безопасность. Проверка ошибок требует времени, поэтому в STL она практически не выполняется. Если вы умеете программировать без ошибок, все замечательно, а если нет - дело кончится катастрофой. Перед включением библиотеки STL в стандартную библиотеку С++ обсуждался вопрос о том, не нужно ли расширить обработку ошибок. Большинство высказались против по двум причинам. О Обработка ошибок снижает быстродействие, а высокая скорость работы попреж-нему остается основной целью большинства про1рамм. Как упоминалось выше, быстродействие было одним из приоритетов при проектировании STL. О Тот, кто ставит на первое место надежность, может добиться своего при помощи интерфейсных оболочек или специальных версий STL. С другой стороны, невозможно повысить быстродействие за счет отказа от проверки ошибок, если эта проверка включена во все базовые операции. Например, если при любой выборке элемента по индексу проверяется, принадлежит ли индекс к интервалу допустимых значений, вам не удастся написать собственную процедуру индексации без проверки. А вот обратная ситуация вполне возможна. В результате проверка ошибок в STL возможна, но не обязательна. В спецификации стандартной библиотеки С++ указано, что любое использование STL, нарушающее предварительные условия, приводит к непредсказуемому поведению. Следовательно, при недействительном индексе, итераторе или 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 |