Предметный указатель
[1] Во время написания этой книги не все компиляторы С++ поддерживали пространства имен. Если ваш компилятор таков, откажитесь от данной директивы. Большинство программ, приводимых нами, используют компиляторы, не поддерживающие пространство имен, поэтому директива using в них отсутствует.
[2] Как было сказано ранее, не все компиляторы поддерживают пространства имен, поэтому эта разница проявляется только для последних версий компиляторов.
[3] Объявление функции inline – это всего лишь подсказка компилятору. Однако компилятор не всегда может сделать функцию встроенной, существуют некоторые ограничения. Подробнее об этом сказано в разделе 7.6.
[4] Вот как выглядит общее решение этой проблемы:
Example2( elemType nval = elemType() ) " _val( nval ) {}
[5] На самом деле для указателей на функции это не совсем так: они отличаются от указателей на данные (см. раздел 7.9).
[6] STL расшифровывается как Standard Template Library. До появления стандартной библиотеки С++ классы vector, string и другие, а также обобщенные алгоритмы входили в отдельную библиотеку с названием STL.
[7] Проверку на неравенство 0 можно опустить. Полностью эквивалентна приведенной и более употребима следующая запись: ptr && *ptr.
[8] До принятия стандарта языка С++ видимость объектов, определенных внутри круглых скобок for, простиралась на весь блок или функцию, содержащую данную инструкцию. Например, употребление двух циклов for внутри одного блока
{
// верно для стандарта С++
// в предыдущих версиях C++ - ошибка: ival определена дважды
for (int ival = 0; ival < size; ++iva1 ) // ...
for (int ival = size-1; ival > 0; ival ) // ...
}
в ранних версиях языка вызывало ошибку: ival определена дважды. В стандарте С++ данный текст синтаксически правилен, так как каждый экземпляр ival является локальным для своего блока.
[9] Замечание. Для упрощения программы мы требуем, чтобы каждое слово было отделено пробелом от скобок и логических операторов. Таким образом, запросы вида
(War || Rights)
Civil&&(War||Rights)
не будут поняты нашей системой. Хотя удобство пользователей не должно приноситься в жертву простоте реализации, мы считаем, что в данном случае можно смириться с таким ограничением.
[10] Иллюстрация Елены Дрискилл (Elena Driskill).
[11] Отметим, что deque не поддерживает операцию reserve()
[12] Существующие на сегодняшний день реализации не поддерживают шаблоны с параметрами по умолчанию. Второй параметр – allocator – инкапсулирует способы выделения и освобождения памяти. В С++ он имеет значение по умолчанию, и его задавать не обязательно. Стандартная реализация использует операторы new и delete. Применение распределителя памяти преследует две цели: упростить реализацию контейнеров путем отделения всех деталей, касающихся работы с памятью, и позволить программисту при желании реализовать собственную стратегию выделения памяти. Определения объектов для компилятора, не поддерживающего значения по умолчанию параметров шаблонов, выглядят следующим образом:
vector< string, allocator > svec;
list< int, allocator > ilist;
[13] Если функция-член push_front() используется часто, следует применять тип deque, а не vector: в deque эта операция реализована наиболее эффективно.
[14] Последняя форма insert() требует, чтобы компилятор работал с шаблонами функций-членов. Если ваш компилятор еще не поддерживает это свойство стандарта С++, то оба контейнера должны быть одного типа, например два списка или два вектора, содержащих элементы одного типа.
[15] Программа компилировалась компилятором, не поддерживающим значений параметров по умолчанию шаблонов. Поэтому нам пришлось явно указать аллокатор:
vector<string,allocator> *lines_of_text;
Для компилятора, полностью соответствующего стандарту С++, достаточно отметить тип элементов:
vector<string> *lines_of_text;
[16] Конечно, в английском языке существуют исключения из правил. Наш эвристический алгоритм превратит crises (множ. число от crisis – прим. перев.) в cris. Ошибочка!
[17] Таким образом, как мы видим, определения встроенных функций могут встретиться в программе несколько раз! – Прим. ред.
[18] Полный текст реализации класса CommandOpt можно найти на Web-сайте издательства Addison-Wesley.
1. Если имеющийся у Вас компилятор пока не поддерживает параметр шаблонов по умолчанию, то конструктору istream_iterator необходимо будет явно передать также и второй аргумент: тип difference_type, способный хранить результат вычитания двух итераторов контейнера, куда помещаются элементы. Например, в разделе 12.2 при изучении программы, которая должна транслироваться компилятором, не поддерживающим параметры шаблонов по умолчанию, мы писали:
typedef vector<string,allocator>::difference_type diff_type
istream_iterator< string, diff_type > input_set1( infile1 ), eos;
istream_iterator< string, diff_type > input_set2( infile2 );
Если бы компилятор полностью удовлетворял стандарту C++, достаточно было бы написать так:
istream_iterator< string > input_set1( infile1 ), eos;
istream_iterator< string > input_set2( infile2 );
1 Более подробное обсуждение этой темы с примерами и приблизительными оценками производительности см. в [LIPPMAN96a].
2 В реальной программе мы объявили бы член _name как имеющий тип string. Здесь он объявлен как C-строка, чтобы отложить рассмотрение вопроса об инициализации членов класса до раздела 14.4.
3 Для тех, кто раньше программировал на C: приведенное выше определение класса Account на C выглядело бы так:
typedef struct {
char *_name;
unsigned int _acct_nmbr;
double _balance;
} Account;
4 См. статью Джерри Шварца в [LIPPMAN96b], где приводится дискуссия по этому поводу и описывается решение, остающееся пока наиболее распространенным.
5 Сигнатура ассоциированного конструктора имеет следующий смысл. Копирующий конструктор применяет некоторое значение к каждому элементу по очереди. Задавая в качестве второго аргумента объект класса, мы делаем создание временного объекта излишним:
explicit vector( size_type n, const T& value=T(), const Allocator&=Allocator());
1 Напомним, что для упрощения реализации необходимо, чтобы между любыми двумя словами, включая скобки и операторы запроса, был пробел. В реальной системе такое требование вряд ли разумно, но мы полагаем, что для вводного курсе, каковым является наша книга, это вполне приемлемо.
2 В объявлении унаследованной виртуальной функции, например eval(), в производном классе ключевое слово virtual необязательно. Компилятор делает правильное заключение на основе сравнения с прототипом функции.
3 Увы! Правые скобки не распознаются, пока OrQuery не выведет все ассоциированное с ним частичное решение.
[19]
Полный текст программы можно найти на FTP-сайте издательства Addison-Wesley по адресу, указанному на задней стороне обложки.
1 Здесь есть потенциальная опасность появления висячей ссылки, если пользователь сохранит адрес какого-либо элемента исходного массива перед тем, как grow() скопирует массив в новую область памяти. См. статью Тома Каргилла в [LIPPMAN96b].
1 Кроме того, программист может устанавливать и сбрасывать флаги состояния формата с помощью функций-членов setf() и unsetf(). Мы их рассматривать не будем; исчерпывающие ответы на вопросы, относящиеся к этой теме, можно получить в [STROUSTRUP97].