Программирование >>  Операторы преобразования типа 

1 ... 39 40 41 [ 42 ] 43 44 45 ... 239


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

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

for edch Ccoll.beg1n(), coll.endO. Интервал

nen fun ref(&Person save)): Операция

Объект функции mem fun ref вызывает заданную функцию класса для того элемента, для которого этот объект вызывается. В приведенном примере для каждого элемента коллекции coil вызывается функция save() класса Person. Разумеется, эта конструкция работает только в том случае, если элемент относится к типу Person или производному от него.

На с. 305 перечислены и более подробно описаны все стандартные объекты функций, функциональные адаптеры и аспекты функциональной композиции. Кроме того, в этом разделе рассказано, как написать собственный объект функции.

Элементы контейнеров

Э.лементы контейнеров должны удовлетворять ряду требований, потому что контейнеры работают с ними по определенным правилам. Настоящий раздел посвящен требованиям, предъявляемым к элементам. Кроме того, мы разберемся, к каким последствиям приводит создание контейнером внутренних копий элементов.

Требования к элементам контейнеров

Контейнеры, итераторы и алгоритмы STL оформлены в виде шаблонов. Это означает, что они могут работать с любыми типами, как заранее определенными, так и пользовательскими. Впрочем, специфика выполняемых операций накладывает ряд требований на элементы контейнеров STL. Таких требований три.

О Требуется возмоэюиость копирования элемента копирующим конструктором. Созданная копия должна быть эквивалентна оригиналу. Это означает, что любая проверка на равенство должна считать копию и оригинал равными, а поведение копии не должно отличаться от поведения оригинала.

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



дотпратить копирование, используя контейнер со ссылочной семантикой. За подробностями обращайтесь на с. 226.

О Требуется возмоэююсть присваивания элемента оператором присваивания. Контейнеры и алгоритмы используют оператор присваивания для замены старых элементов новыми.

О Требуется возможность уничтожения элемента деструктором. Контейнеры уничтожают свои внутренние копии элементов при удалении этих элементов из контейнера. Следовательно, деструктор не должен быть закрытым (private). Кроме того, как обычно в С++, деструктор не должен инициировать исключения, иначе возможны абсолютно непредсказуемые последствия.

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

Кроме того, к элементам могут предъявляться дополнительные требования

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

О Для некоторых операций требуется определить проверку на равенство оператором ==. Такая необходимость особенно часто возникает при поиске.

О Для ассоциативных контейнеров требуется, чтобы элементы поддерживали критерий сортировки. По умолчанию используется оператор <, вызываемый объектом функции iesso.

Семантика значений и ссылочная семантика

Все контейнеры создают внутренние копии своих элементов и возвращают эти копии. Следовательно, элементы контейнера равны, но не идентичны объектам, заносимым в контейнер. При модификации объектов, являющихся элементами К01ггейнера, вы модифицируете копию, а ие исходный объект.

Копирование значений означает, что контейнеры STL поддерживают семантику значений. Они содержат значения вставляемых объектов, а не сами объекты. Но на практике также возникает необходимость в ссылочной семантике, при которой контейнеры содержат ссылки на объекты, являющиеся их элементами.

В некоторых старых системах С++ приходится обеспечивать выполнение этих дополнительных требований, даже если оии ие используются в программе. Например, некоторые реализации vector требуют обязательного наличия деструктора по умолчанию для элементов. В других реализациях всегда должен присутствовать оператор ciJasEie-ния. В соответствии со стандартом эти требования незаконны; скорее всего, в будущем подобные ограничения будут устранены.



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

Принятый в STL подход, то есть поддержка только семантики значений, имеет свои положительные и отрицательные стороны. К достоинствам такого подхода относятся:

О простота копирования элементов;

О при использовании ссылок часто возникают ошибки (программист должен следить за тем, чтобы ссылки не относились к несуществующим объектам, кроме того, необходимо предусмотреть обработку возможных циклических ссылок).

Недостатки:

О при отказе от ссылочной семантики копирование элементов может выполняться неэффективно или становится невозможным;

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

На практике нужны оба подхода: копии, независимые от исходных данных (семантика значений), и копии, ссылающиеся на исходные данные и изменяющиеся вместе с ними (ссылочная семантика). К сожалению, стандартная библиотека С++ не поддерживает ссылочную семантику. Впрочем, ее можно реализовать в контексте семантики значений.

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

Более разумное решение основано на применении умных указателей - объектов, поддерживающих интерфейс указателей, но выполняющих дополнительную внутреннюю проверку или другие операции. Но здесь возникает важный вопрос: насколько умными должны быть эти указатели? В стандартную библиотеку С++ входит класс умного указателя auto ptr (см. с. 54), который на первый взгляд мог бы пригодиться, к сожалению, этот класс не подходит, поскольку не удовлетворяет одному из основных требований к элементам контейнеров, а именно: после копирования или присваивания объектов класса auto ptr оригинал и копия не эквивалентны. Исходный объект auto ptr изменяется, потому что значение передается, а не копируется (см. с. 59 и 62). На практике это означает, что сортировка и даже простой вывод элементов контейнера может привести к их уничтожению. Следовательно, объекты auto ptr 7ie должны использоваться как элементы контейнеров (в системе С++, соответствующей стандарту, такие попытки приводят к ошибкам компиляции). Дополнительная информация приведена на с. 59.

Чтобы реализовать ссылочную семантику для контейнеров STL, вам придется написать собственны!! класс умного указателя. Но будьте внимательны: исполь-



1 ... 39 40 41 [ 42 ] 43 44 45 ... 239

© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика