|
Программирование >> Полиморфизм без виртуальных функций в с++
Однако оставление void* небезопасным можно считать приемлемым, поскольку все знают - или, по крайней мере, должны знать, - что приведения из типа void* - это хитрость. Подобные примеры приобретают практический интерес, когда вы начинаете строить классы, которые могут содержать много разных указателей (например, чтобы минимизировать объем сгенерированного кода, см. раздел 15.5). Объединения (union) и использование многоточия для явного подавления проверки типов - это тоже дыры в механизме защиты от неявного нарушения константности. Однако я предпочитаю систему, в которой есть несколько прорех , той, которая вообще не предоставляет никакой защиты. Как и в случае с void*, программисты должны понимать, что объединения и отказ от контроля аргументов опасны, что их следует по возможности избегать, а при.менять с особой осторожностью и только в случае необходимости. 14.3.5. Преимущества новых приведений типов Новые операторы приведения типов направлены на минимизацию и локализацию небезопасных и подверженных ошибкам приемов программирования. В данном разделе рассматриваются ситуации, связанные с этой проблематикой (старые приведения типов, неявные сужающие преобразования и функции преобразования), и возможности преобразования существующего кода с учетом новых операторов приведения. 14.3.5.1. Старые приведения типов Вводя новый стиль приведения типов, я хотел полностью заменить нотацию (Т) е, объявив ее устаревшим синтаксисом. В тако.м случае комитет должен был предупредить пользователей о том, что нотацию {Т) е могут исключить из следующего стандарта С++. Я видел прямые параллели между такой акцией и введением в стандарт ANSI/ISO С прототипов функций в стиле С-и-, когда неконтролируемые вызовы были объявлены устаревшими. Однако предложение не нашло должного отклика у большинства членов комитета, поэтому очистка С++, по-видимому, никогда не произойдет. Важнее, однако, то, что новые операторы приведения дают некоторую возможность уйти от небезопасных конструкций, если есть мнение, что безопасность важнее обратной совместимости с С. Новый синтаксис приведения может быть также поддержан предупреждениями компилятора против использования старых приведений типов. Благодаря новым операторам приведения становится возможен более безопасный, но не менее эффективный стиль программирования. Очевидно, важность этого аспекта начнет возрастать по мере того, как будет повышаться общее качество кода, а новые инструментальные средства, ориентированные на безопасность типов, найдут широкое применение. Это относится как к С++, так и к другим языкам. 14.3.5.2. Неявные сужающие преобразования Идея уменьшить число нарушений статической системы типов и сделать их по возможности очевидными лежит в основе всей работы над новым синтаксисом приведений. Разумеется, в этом контексте еще раз рассматривалась возможность устранения неявных сужающих преобразований, таких как long в int и double в char (см. раздел 2.6.1). К сожалению, их полный запрет не только недостижим, но и вреден. Главная проблема в том, что при выполнении арифметических операций может происходить переполнение: void f(char с, short s, int i) { С++; результат может не поместиться в char S++; результат может не поместиться в short i++; может произойти переполнение Если запретить неявное сужение диапазона, то операции С++ и s++ станут недопустимыми, поскольку объекты типа char и short преобразуются в int перед выполнением арифметических действий. Если требовать, чтобы сужающие преобразования всегда задавались явно, этот пример пришлось бы переписать так: void f(char с, short s, int i) { с = static cast<char>(c+l); с = static cast<short>{s+l); i++; Я не надеюсь, что такая нотация приживется, если у нее нет какого-либо очевидного преимущества. А в чем преимущество такой записи? Загрязнение кода явными приведениями никак не улучшает его ясности и даже не уменьшает число ошибок, поскольку пользователи будут применять операторы приведения, не слишком задумываясь. Конструкция i++ также небезопасна из-за воз.можности переполнения. Добавление явных приведений бывает даже вредным, поскольку компилятор по умолчанию может вставлять код для обработки переполнений во время исполнения, а явное приведение будет подавлять этот механизм. Лучше было бы определить dynamic cast так, чтобы данный оператор во время исполнения осуществлял проверку значения числового операнда. Тогда пользователи, для которых подобный контроль важен, могли бы при необходимости применять это средство. Также допустимо написать функции для проверки (см. раздел 15.6.2), например: template<class V, class U> V narrow{U u) { V V = U; if (v!=u) throw bad narrowing; return v; Несмотря на то что полный запрет сужающих преобразований невозможен и потребовал бы серьезного пересмотра правил выполнения арифметических операций, остается еще целый ряд преобразований, против которых компилятор .мог бы предупреждать достаточно уверенно: преобразование типа с плавающей точкой в интегральный, long в short и long в char. В Cfront так всегда и происходило. Остальные потенциально сужающие преобразования, например, int в float и int в char часто безвредны, чтобы пользователи смирились с предупреждениями компилятора. 14.3.5.3. Нотация вызова конструктора С++ поддерживает нотацию конструктора T(v) как сино1П1М (Т) v старого приведения типов. Было бы лучше переопределить т (v) как аналог допустимого конструирования объекта (как во время инициализации): Т val(v); Такое изменение, для которого, к сожалению, не придумано подходящего названия, потребовало бы времени, поскольку из-за него перестает работать существующий код (к тому же результату приводит и предложение объявить (т) v устаревшей конструкцией). Но данное предложение не получило поддержки в комитете. Правда, пользователи, которые хотят применить явную форму неявного преобразования (допустим, для устранения неоднозначности), могут написать для этого шаблон класса (см. раздел 15.6.2). 14.3.5.4. Использование новых приведений Можно ли пользоваться новыми приведениями, ие понимая всех описанных выше тонкостей? Удастся ли без особых сложностей преобразовать код, где использовались старые приведения типов, к новому стилю? Чтобы новый синтаксис вытеснил прежний, ответ на оба вопроса должен быть положительным. Проще всего было бы во всех случаях подставить stat ic cast и посмотреть, как отреагирует компилятор. Каждую ошибку, если таковые возникнут в ходе компиляции, придется анализировать отдельно. Если проблема связа1ш с нарушением константности, посмотрите, действителыга ли приведение нарушает систему типов; если не нарушает, следует использовать const cast. В ситуации, когда сложности возникли с неполными типами, указателями на функции или приведением между несоотносимыми типами, убедитесь, что получившийся указатель все-таки приводится к исходному типу. Если же неприятность касается преобразования указателя на int (или схожих действий), то стоит лишний раз подумать, зачем это было сделано; если устранить такое преобразование не удается, reinterpret cast сделает то же самое, что в таких случаях делали старые приведения типов. Обычно подобный анализ и устранение старых приведений может вьпюлнить не слишком сложная программа. Но все равно было бы лучше удалить все имеющиеся приведения.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |