Раз уж мы затронули тему предупреждений, стоит заметить, что они по своей природе зависимы от реализации, поэтому не следует слишком расслабляться и перекладывать на компилятор обнаружение ваших ошибок. Например, код с сокрытием функции, приведенный выше, проходит через другой (к сожалению, широко распространенный) компилятор без каких-либо предупреждений.
• Принимайте всерьез предупреждения компилятора и старайтесь добиться того, чтобы ваш код вообще не вызывал предупреждений, даже при задании максимального уровня диагностики.
• Не впадайте в зависимость от предупреждений компилятора, потому что разные компиляторы предупреждают о разных вещах. При переходе на новый компилятор могут пропасть некоторые предупреждения, на которые вы привыкли полагаться.
Правило 54: Ознакомьтесь со стандартной библиотекой, включая TR1
Стандарт C++ (документ, описывающий язык и его библиотеку) был ратифицирован в 1998 году. В 2003 году были внесены небольшие изменения, исправляющие ошибки. Комитет по стандартизации, однако, продолжает работать, и появление «Версии 2.0» стандарта C++ ожидается примерно в 2008 году. Неопределенность относительно точной даты объясняет, почему обычно при ссылке на следующую версию C++ говорят «С++0х» (версию C++ 200х-го года).
Предположительно, C++0x будет описывать некоторые интересные дополнения к самому языку, но большая часть новой функциональности C++ будет иметь вид добавлений к стандартной библиотеке. Мы уже знаем кое-что из того, что появится в библиотеке, потому что это специфицировано в документе, известном под названием TR1 («Technical Report 1»), созданном рабочей группой по библиотеке C++. Комитет по стандартизации сохраняет за собой право модифицировать описанную в TR1 функциональность, прежде чем она будет включена в официальный стандарт C++0x, но существенные изменения маловероятны. С практической точки зрения, TR1 возвещает начало новой редакции C++, которую можно было бы назвать стандартом C++ 1.1. Нельзя быть эффективно работающим программистом C++, не будучи знакомым с функциональностью, описанной в TR1, потому что она полезна для библиотек и приложений почти любого типа.
Прежде чем дать краткий обзор того, что включено в TR1, стоит вспомнить основные части стандартной библиотеки C++, специфицированные в C++98:
• Стандартная библиотека шаблонов (STL), включающая контейнеры (vector, string, map и т. п.); итераторы; алгоритмы (find, sort, transform и т. п.); функциональные объекты (less, greater и т. п.) и различные адаптеры контейнеров и функциональных объектов (stack, priority_queue, mem_fun, not1 и т. п.).
• Потоки ввода-вывода (iostreams), включая поддержку определенной пользователем буферизации, интернационализацию ввода-вывода и предопределенные объекты – cin, cout, cerr и clog.
• Поддержка интернационализации, включая возможность иметь несколько активных локалей. Типы наподобие wchar_t (обычно 16-битные char) и wstring (строки, состоящие из wchar_t), облегчающие работу с кодировкой Unicode.
• Поддержка численных методов, включая шаблоны для комплексных чисел (complex) и массивы чистых значений (valarray).
• Иерархия исключений, включая базовый класс exception, производные от него – logic_error и runtime_error, а также разнообразные классы, наследующие этим.
• Стандартная библиотека C89. Все, что есть в стандартной библиотеке C 1989 года, есть и в C++.
Если что-то из перечисленного вам незнакомо, я советую найти время и исправить ситуацию, обратившись к вашему любимому руководству по C++.
TR1 специфицирует 14 новых компонентов библиотеки. Все они находятся в пространстве имен std, точнее, во вложенном пространстве tr1. Таким образом, полное наименование компонента TR1 shared_ptr (см. ниже) – std::tr1::shared_ptr. В этой книге я иногда пропускаю std::, когда говорю о компонентах стандартной библиотеки, но всегда указываю префикс tr1::.
В настоящей книге были приведены примеры следующих компонентов TR1:
• «Интеллектуальные» указатели tr1::shared_ptr и tr1::weak_ptr. tr1::shared_ptr работает как встроенный указатель, но отслеживает, сколько экземпляров tr1::shared_ptr указывает на объект. Этот прием называется
tr1::shared_ptr, может быть, наиболее полезный компонент TR1. Я многократно прибегал к нему в этой книге, в том числе в правиле 13, где объяснял, почему это так важно. (К сожалению, в книге не нашлось места для tr1::weak_ptr.)
• tr1::function дает возможность представить любую
void registerCallback(std::string func(int)); // типом параметра
// является функция
// принимающая int и
// возвращающая string
Имя параметра – func – необязательно, поэтому registerCallback может быть объявлена и так:
void registerCallback(std::string (int)); // то же, что выше; имя
// параметра опущено
Отметим, что «std::string (int)» – это сигнатура функции. tr1::function позволяет сделать функцию registerCallback намного более гибкой за счет того, что ее аргументом может быть любая вызываемая сущность, которая принимает параметр int или
void registerCallback(std::tr1::function<std::string (int)> func);
// параметр func – это любая вызываемая
// сущность с сигнатурой, совместимой
// с “std::string (int)”
Гибкость такого рода удивительно удобна. Я постарался продемонстрировать ее в правиле 35.
• tr1::bind делает все, на что способны адаптеры-связыватели STL bind1st и bind2nd, плюс многое другое. В отличие от связывателей, существовавших до TR1, tr1::bind может работать как с константными, так и с неконстантными функциями-членами. Допускаются также параметры, передаваемые по ссылке. Кроме того, в отличие от старых связывателей, tr1::bind не нуждается в помощи со стороны при работе с указателями на функции, поэтому обращаться к ptr_fun, mem_fun или mem_fun_ref перед вызовом tr1::bind больше нет нужды. Проще говоря, tr1::bind – это связыватель второго поколения, которое существенно лучше своих предшественников. Пример использования я привел в правиле 35.
Прочие компоненты TR1 я разделил на две группы. Первая группа представляет довольно дискретную,