Б. Страуструп - Дизайн и Эволюция C++. 2006 (1160775), страница 84
Текст из файла (страница 84)
А в чем преимушество такой записи7 Загрязнение кода явными приведениями никак не улучшает его ясности и даже не уменьшает число ошибок, поскольку пользователи будут применять операторы приведения, не слишком задумываясь. Конструкция 1+а также небезопасна из-за возможности переполнения. Добавление явных приведений бывает даже вредным, поскольку компилятор по умолчанию может вставлять код для обработки переполнений во время исполнения, а явное приведение будет подавлять этот механизм. Лучше было бы определить <1упапйс саве так, чтобы данный оператор во время исполнения осуществлял проверку значения числового операнда. Тогда пользователи, для которых подобный контроль важен, могли бы при необходимости применять это средство. Также допустимо написать функции для проверки (см.
раздел (5.6.2), например: семр1аге<с1авв ч, с1авв о> ч паггоищ и) ( Чч=п; гг (ч(=п) Шгом Ьас) паггон1прл геспгп ч; ) Несмотря на то что полный запрет сужаюших преобразований невозможен и потребовал бы серьезного пересмотра правил выполнения арифметических операций, остается еше целый ряд преобразований, против которых компилятор мог приведений. Разумеется, в этом контексте еще раз рассматривалась возможность устранения неявных сужаюших преобразований, таких как 1опд в 1пС и с)оп)>1е в с)гаг (см. раздел 2.6.)).
К сожалению, их полный запрет не только недостижим, но и вреден. Главная проблема в том, что при выполнении арифметических операций может происходить переполнение: НИИИИИИВ Приведение типов бы предупреждать достаточно уверенно: преобразование типа с плавающей точкой в интегральный, 1опд в эйогс н 1опо в с наг. В С1гопг так всегда и происходило. Остальные потенциально сужающие преобразования, например, 1пс в 11оас и 1пс в спас часто безвредны, чтобы пользователи смирились с предупреждениями компилятора.
14.3.5.3. Нотация вызова конструктора С++ поддерживает нотацию конструктора т (ч( как синоним (т) ч старого приведения типов. Было бы лучше переопределить т (ч) как аналог допустимого конструирования объекта (как во время инициализации): т на1(ч(; Такое изменение, для которого, к сожалению, не придумано подходящего названия, потребовало бы времени, поскольку из-за него перестает работать су|пествуюший код (к тому же результату приводит и предложение объявить (т) ч устаревшей конструкцией). Но данное предложение не получило поддержки в комитете.
Правда, пользователи, которые хотят применить явную форму неявного преобразования (допустим, для устранения неоднозначности), могут написать для этого шаблон класса (см. раздел 15.6.2). 14,3.5.4. Использование новых приведений Можно ли пользоваться новыми приведениями, пе понимая всех описанных выше тонкостей? Удастся ли без особых сложностей преобразовать код, где использовались старые приведения типов, к новому стилю? Чтобы новый синтаксис вытеснил прежний, ответ на оба вопроса должен быть положительным.
Проще всего было бы во всех случаях подставить эса сто санс и посмотреть, как отреагирует компилятор. Каждую ошибку, если таковые возникнут в ходе компиляции, придется анализировать отдельно. Если проблема связана с нарушением константности, посмотрите, действительно ли приведение нарушает систему типов; если не нарушает, следует использовать сопэс санс. В ситуации, когда сложности возникли с неполными типами, указателями на функции нли приведением между несоотносимыми типамн, убедитесь, что получившийся указатель все-таки приводится к исходному типу. Если же неприятность касается преобразования указателя на 1пс (или схожих действий), то стоит лишний раз подумать, зачем это было сделано; если устранить такое преобразование не удается, гетпсехргес санс сделает то же самое, что в таких случаях делали старые приведения типов. Обычно подобный анализ и устранение старых приведений может выполнить не слишком сложная программа.
Но все равно было бы лучше удалить все имеющиеся приведения. Глава 15. Шаблоны Ничто не дается с таким трудом, не оставляет столько сомнений в успехе и не сопряжено с большим риском, чем установление нового порядка вещей. Никколо Макиаввлли 15.1. Введение Шаблоны и исключения были специально упомянуты в статье «%'Ьаг!з?» [8ггоцзггцр, 1986Ь1 как желательные в С++ (см. раздел 3.15).
Проектирование этих средств описано в работах [Ягоцзггпр, 1988Ь1„[Коеп!8, 1989Ь1, [Коеп!8, 19901 и в АКМ, а их включение в язык отражено в предложениях по стандартизации С++. Первопричина появления шаблонов — желание параметрнзовать контейнерные классы. Механизм же исключений есть в языке, потому что изначально хотелось располагать стандартным способом обработки ошибок во время выполнения. В обоих случаях С предоставлял лишь очень примитивные средства, которые не позволяли программисту явно выразить свои намерения н не слишком хорошо совмещались с ключевыми концепциями С++. Еще со времен С кт!1Ь С!аззез мы пользовались макросами для параметризации контейнеров (см. раздел 2.9.2), но макросы в С не могут работать с областями действия и типами и плохо увязываются с инструментальными средствами.
Механизмы, которые в ранних версиях С++ использовались для обработки ошибок — имеются в виду вес эгвргг1опдэпр и индикаторы типа ег гпо, — плохо сочетались с конструкторами и деструкторами. Отсутствие таких механизмов приводило к неудачному проектированию, кодированию на излишне низком уровне и трудностям при совместном использовании библиотек, полученных из различных источников, то есть затрудняло работу на нужном (высоком) уровне абстракции. На мой взгляд, шаблоны и исключения — это две стороны одной медали.
Первые позволяют уменьшить число ошибок во время выполнения, расширяя спектр задач, с которыми может справиться статическая система типов. В свою очередь, исключения дают механизм для обработки оставшихся ошибок. С помощью шаблонов до разумного уровня можно довести число ошибок времени выполнения, которые обрабатываются с помощью исключений. Исключения предоставляют библиотекам, основанным на шаблонах, возможность уведомить вызывающую программу об ошибках. ИИИШИИИИИ Шаблоны 152. Зачем нужны шаблоны В первоначальном проекте С+я- параметризованные типы рассматривались, но их пришлось отложить из-за нехватки времени на тщательное изучение вопросов проектирования и реализации, а также из-за боязни слишком усложнить компилятор.
В частности, меня беспокоило, что неудачное проектирование может стать причиной замедления компиляции и компоновки. Я также считал, что удачная поддержка параметризованных типов значительно увеличит время, необходимое для переноса на другие платформы.
К несчастью, мои опасения полностью подтвердились. Шаблоны считались чрезвычайно важными средствами для правильного проектирования контейнерных классов. Впервые проект шаблонов был представлен на конференции 138Е1ь11Х по С++, состоявшейся в 1988 г. в Денвере [Бггопзсгпр, 1988Ь1. В конце своего выступления я сказал: «В контякств С++ вопросы стаэятся следующим образом: Ы можно ли сделать парамятризацию типа простой для примяненият сг удастся ли обьэкты парамятриэояонного типа использоэать ток жв эффяктияно, как и обьекты «жяспсо заданногаэ типот С1 можно ли интэгрироэать я С++ парамятриэояанныэ типы общего эидат 1З возможно ли реапизоэать парамвтризоэанные типы ток, чтобм скорость компиляции и компоновки была сравнима с той, которую обяспечияавт система разработки, нэ поддяржнэающая порамятризацию типоэт СЗ удастся пи сделать такую систэму компиляции простой и переносимойтз Таковы были мои критерии проектирования шаблонов.
Конечно, сам я был уверен, что на все эти вопросы удастся ответить положительно. Я утверждал, что фундаментальные альтернативы выглядят так: «При написании стандартной библиотвки сталкиваешься с сярьязной проблемой — я С++ не предостаялвно общих срядстэ определения кконтвйнврных классояэ: спнскоэ, векторов, ассоциатиэных массивов и т.д. Есть дяа подхода к реализации таких классов: ьз э 5юа1йа1к — опора на динамическую систему типоэ и наследование; сг я С1а — на статическую систэму типов и средства для работы с аргумвнтами обобщенно. го типа 1уря. Первый подход очвнь гибок, но сяяэан с высокими затратами и, что яажнее, нэ позволяет статической системе типов обнаружить ошибки интерфейса.
Второй традиционно ведет к довольно сложной реализации; средства компиляции и компоновки при этом тожв излингнв сложны. Этому подходу также сэойстэанна недостаточная гибкость, поскольку языки, э которых он нспользояался, праждв эсвго Аг1а, ня имеют механизма наследования. Изначально нам хотелось имэть э С++ механизм, так жя хорошо структурированный, как э С1о, н нмвющий столь жя хорошие характеристики по ярвмяни исполнения и расходу памяти, но значительно быстрвя компилируемый. Еще он должен быть таким жэ гибким, как э 5юа111а11г.