В этот блог-пост вошли соображения, которые не хотелось впихивать в предыдущий пост дабы не раздувать его размер совсем уж до безобразия.
Попробую рассказать о том, как я сам сейчас отношусь к существующей в C++ поддержке исключений.
Ключевое
Хорошо, что исключения в C++ есть. Как уже говорилось в предыдущем посте, лично я плохо себе представляю как писать надежный код без использования исключений при программировании в стиле "современного C++".
Плохо то, что текущая реализация исключений:
- во-первых, ставит разработчика перед выбором об использовании или неиспользовании исключений в принципе;
- во-вторых, даже при использовании исключений не всегда легко понять, стоит ли в каком-то конкретном месте применять исключения или же нет. Просто из соображений скорости работы кода.
А все потому, что сейчас исключения слишком дорогие (тяжелые). Это касается и стоимости бросания исключений, и стоимости хранения в исполняемом файле информации для поиска обработчиков исключений (что-то вроде урезанной версии RTTI). Плюс к тому, исключения не предсказуемы в том плане, что заранее не просчитаешь, сколько же займет выброс и обработка исключения, что не позволяет применять исключения в системах жесткого реального времени.
Поэтому главная претензия к существующим в C++ исключениям -- это их высокая стоимость из-за чего в ряде случаев приходится от использования исключений отказываться. А это ведет к зоопарку способов информирования об ошибках и к фрагментации C++ной экосистемы.
Что еще мне не нравится в существующем C++
Ниже попробую коротко пройтись по другим моментам, которые мне не нравятся в текущем C++. Не думаю, однако, что эти пункты когда-либо будут исправлены. Но это же не повод не написать о том, что гложет, не так ли? ;)
Возможность выбросить всё, что угодно
Если я правильно понимаю, когда в C++ добавили возможность работы с исключениями, стандартных базовых классов для исключений (std::exception, std::runtime_error и т.д.) еще не было. Поэтому в C++ можно бросить не только класс-наследник std::exception, но и простой int или const char *.
Лично я думаю, что это дурацкое наследие темного прошлого, от которого нужно избавиться раз и навсегда.
Сам я придерживаюсь правила о том, что все бросаемые в коде исключения должны быть наследниками std::exception. И, по большому счету, пишу код, который может не пережить, если кто-то бросит простой int. Не то, чтобы я много писал чего-то вроде:
try { ... } catch(const std::exception &) { ... // Отмена каких-то операций. throw; // Проброс исходного исключения дальше. } |
Но иногда приходится. И не всегда я вспоминаю о том, что желательно было бы добавить еще и catch(...), а это может выйти боком когда-нибудь.
Иерархии исключений
Очень неоднозначная штука, которая изначально мне очень нравилась, но потом перестала.
С одной стороны, удобно, когда можно завести базовый класс для всех исключений библиотеки X. Тогда элементарно просто отлавливать все исключения, которые могут вылетать из X.
С другой стороны, мне сложно припомнить когда на практике была бы польза от развесистых иерархий классов исключений. Обычно хватает какого-то одного класса, куда описание возникшей проблемы складывается в виде строки.
При этом, насколько я понимаю, именно наличие таких иерархий является одной из причин высокой стоимости поддержки исключений: в программе нужно иметь какой-то вариант RTTI для того, чтобы разбираться с наследованием, а при пробросе исключения нужно посредством этого варианта RTTI искать подходящий обработчик для исключения.
Так что штука хорошая, но дорогая. И, может быть, если бы в C++ ограничились более простой версией (возможность объявить собственный тип исключения, но без возможности наследоваться от него), то это бы привело к более дешевой поддержке исключений. А это бы сузило круг задач, в которых исключения находятся под запретом.
Недоделанный noexcept
Повторяться не буду, т.к. писал уже неоднократно, в том числе и в прошлом посте. Но тезисно обозначу, что кроме спецификатора noexcept и выражения noexcept, в C++ мне очень не хватает noexcept-блока. Чтобы компилятор бил меня по рукам, если написал не-noexcept код внутри noexcept-блока.
Пару слов о предложении добавить в C++ т.н. deterministic exceptions
Несколько лет назад Герб Саттер написал предложение по добавлению в C++ т.н. deterministic exceptions: Zero-overhead deterministic exceptions: Throwing values (ссылка дана на последнюю на момент написания этих строк ревизию).
Лично я скептически отношусь к этому предложению.
Да, там правильно говорится о том, что существующие динамические исключения не могут использоваться в определенных областях и это плохо. Исключения все-таки нужны, но a) гораздо более легковесные и b) с предсказуемым временем обработки.
Но вот альтернатива в виде предлагаемых deterministics exceptions не решает проблему существующих исключений. А вводит в язык еще один механизм, у которого есть свои достоинства и недостатки.
В итоге может получиться как в известном комиксе: у нас есть 14 конкурирующих стандартов и с этим нужно что-то сделать... Хоба! И у нас уже 15 конкурирующих стандартов.
Раньше у нас были возвращаемые значения (разных видов) и динамические исключения. Плюс недоделанный noexcept. А если Саттеровское предложение примут, то к этому зоопарку добавятся еще и deterministic exceptions. После чего разработчиков оставят заниматься любовью со всем тем бардаком, который уже накопился в C++ мире.
Так что, имхо, нужно фиксить существующий механизм исключений (возможно даже путем слома совместимости между стандартами), а не добавлять еще один способ выстрелить себе в ногу.
Кстати говоря, в свое время я уже фиксировал краткие впечатления от предложений Саттера, желающие могут найти их здесь. С тех пор ничего принципиально не поменялось. И да, за предложение валить все приложение вместо выбрасывания bad_alloc нужно отрывать руки. Не глядя на авторитеты и заслуги.
Тут новое предложение в комитет по стандартизации подвезли: P2232
Только недавно узнал, совершенно случайно.
P2232: Zero-Overhead Deterministic Exceptions: Catching Values.
Если оттуда исключить дурацкие (сорри за мое оценочное суждение) идеи по бросанию и поимке сразу нескольких экземпляров исключений, то может получиться интереснее, чем в предложениях Саттера. Почти как то, что я сам бы хотел видеть.
Что хотелось бы видеть в C++ (но вряд ли это был бы C++)
Не буду здесь еще раз повторять то, что однажды уже было сформулировано с примерами и пояснениями. Поэтому дам ссылку на блог-пост годичной давности: "Какой способ информирования об ошибках мне бы хотелось иметь для написания надежного кода?"
То, что там было написано год назад все еще является моим актуальным мнением.
Комментариев нет:
Отправить комментарий