Pull to refresh

Comments 42

После работы с исключениями в управляемом коде (на примере C#) исключения в плюсах кажутся крайне топорными, даже в последнем стандарте.
Мне было бы приятно иметь в шарпе noexcept
Для чего, если не секрет? Если я правильно понимаю, noexcept используется для того, чтобы быть уверенным, что в результате выброса исключения не потеряется указатель на ресурс, который необходимо освободить — тогда при нарушении гарантии выпадет вся программа и это будет заметно. В .NET наличие GC делает эту проблему крайне редкой, а если вам всё же принципиально, можно попробовать воспользоваться такой экзотической вещью, как CriticalFinalizerObject.
Существенные отличия, на мой взгляд, есть:

1. System.Exception является reference-type объектом, который всегда передается по ссылке без копирования, благодаря чему отпадает необходимость в отдельном типе exception_ptr и всех функциях, работающих с ним.
2. Вложенные исключения доступны в виде поля Exception.InnerException и для них не нужны особые механизмы обработки.
Ой ну ладно, раньше было в c#, теперь догадались и сделали и в с++.

Я признаю, что С# более чем навороченный язык, но конкретно в исключениях, особенно с данными нововвидениями, разницы-то уже особо и нет — теперь-то можно и то и то.

Просто реализовали это на 10 лет позже, это да, но такова уж плата за #стабильность.
UPD: кое-что забыл.
3. Удобное поле Exception.StackTrace, не зависит от платформы и не требует лишних телодвижений.
В языке, официально поддерживаемым только на одной платформе?
Ха, в виндах я тоже легко стектрейс получу.
А так, моно — тот же код под другую платформу, как это было бы на c++, только написанный другими людьми.
Что вам далась эта «официальная поддерживаемость»? Проект Mono уже давно не кустарная поделка, им вполне можно пользоваться.
Поле StackTrace входит в стандартную библиотеку, а значит есть на любой платформе, которая ее реализует, и его не нужно изобретать самому.
Я не знаю. Я не работаю с моно. Но от коллег-разработчиков постоянно слышу, что поддержка, конечно, есть, но шаг влево-шаг вправо (WPF, кажется, например) — и уже нет поддержки. Конкретные технологии не назову.

>> Поле StackTrace входит в стандартную библиотеку, а значит есть на любой платформе, которая ее реализует, и его не нужно изобретать самому.
Функция PrintBackTrace есть в любой приличной компании, ее тоже никто не изобретает. Просто черзе ifdef для gcc и msvc реализовать поддержку. 1 раз.
Дальше следует очередное нытье по поводу отсутствия блока finally…
в C++ этот блок не нужен ибо есть деструкторы и RAII
А с помощью этого как-то можно сделать так, чтобы при выпадаении необработанного исключения печатался stack trace подобной java без существенных модификаций программы?
В любой приличной компании, есть метод PrintBackTrace, реализация которого, специфична для ОС.
Обладая этим методом, добавление его в terminate колбек приводит к нужному результату.
Только в DEBUG-сборке стек хорошо раскручивается.
Если компилировать проект с максимальными оптимизациями, StackTrace в большинстве случаев падений недоступен.
на маке при падении окошко само вылезает, на линуксе можно подцепиться, есть например Убунтовский apport, а в винде регаем что-нибудь как post mortem debugger и смотрим себе спокойно стек.
Вообще ведь все эти эксепшены ориентированы не на ситуацию, когда после них программа тупо падает, даже выводя чего-нибудь информативное.

Их суть в удобной обработке редко возникающих ошибок. Именно обработке, после которой программа продолжает нормальную работу, без утечек памяти и прочих неприятностей.

Так что, на мой взгляд, отсутствие в стандарте функции стэк трейса неудивительно. Для этого, как сказали выше, можно использовать всякие сторонние средства.
Можно, если программа собрана с отладочной инфой. Но, почему-то никто так не делает.
Может потому что она или тормозит или много весит в зависимости от настроек, а стрипают в дебаг символы в отдельные пакеты только в Линуксах?
Очень познавательно. Большое спасибо!
Скажите, пожалуйста, это вы со стандарта все или где-то в компактном виде нашли?
Часть информации брал с cppreference.com, но там не полное описание, пришлось в стандарт заглядывать
А как можно с std::exception_ptr вынуть исключение не используя (даже косвенно) std::rethrow_exception?
Я думаю, никак. Ведь std::exception_ptr хранит просто указатель и не хранит тип. Поэтому std::exception_ptr нельзя разыменовать. Ведь неизвестно, какого именно типа исключение.
Думал, может что-то типа dynamic_cast (но без std::rethrow_exception).
Ааа, ну если тип исключения известен, то способ, навеное есть. Только он может быть некрасивым, типа попытки прочитать private поля std::exception_ptr
Спорная это штука — noexcept… мы в свое время от использования пустого throw() в объявлениях функций отказались, так как это получалась ужасно деструктивная конструкция — в С++ очень много вещей, способных бросить исключение, и черемерное увлечение throw() приводило к падению программ в ситуациях, когда исключение было-бы обработано без проблем. Никакой пользы от throw() не было — один вред.

Теперь с этой новой конструкцией noexcept, нет никакого улучшения, кроме обещания, что компиляторы будут проверять условие во время компиляции (сомнительно, что смогут в реальной жизни из-за виртуальных функций, и еще более сомнительно, что все разработчики компиляторов сделают это единообразно).

То есть фича получилась только для разработчиков стандартной библиотеки, и даже там не везде будет применимо, ИМХО.

А народ будет ее пытаться в реальном коде использовать, и наступать на те-же грабли, что и с throw().
Не понял аргумент про throw. Почему
черемерное увлечение throw() приводило к падению программ в ситуациях, когда исключение было-бы обработано без проблем.
?
попытка выбросить исключение, не соотвествующее спецификации throw(), из функции, приводит к вызову std::unexpected() и аварийному завершению программы.

Теперь народ навешивает throw() на всякие тривиальные однострочные функции, свято веря, что они ни при каких обстоятельствах не бросают исключений. А про копирование объектов забывают, и в результате рано или поздно мы попадаем в std::unexpected(). А без спецификаций исключение было-бы корректно обработано и записано в лог.
Но, в общем то, польза в формальной спецификации exception-safety есть. Как минимум, когда я пишу exception-safety код, я обращаю внимание на спецификацию вызываемых функций. Это даёт возможность не использовать лишний раз RAII, при должном кодировании.

Также nothrow спецификация move конструкторов требуется в контейнерах, чтобы гарантировать безопасное перемещение элементов.

Безусловно, лучше не писать nothrow, если нет уверенности. В C++ полно вещей, которыми можно отстреливать ноги :)

А сам nothrow лишь возможность вынести спецификации на уровень языка (и дать возможность анализировать её компилятору) и избавиться от, как минимум, возможных утечек памяти, и, как максимум, от Undefined behavior.
Как минимум, когда я пишу exception-safety код, я обращаю внимание на спецификацию вызываемых функций.


Вы проверяете, и я проверяю (и то я себе в данном случае не доверяю), а 10 соседей не проверяют — как можно потом на результат положиться? Мы поэтому и отказались от throw(), так как компилятор ничего не проверяет, а отследить вручную корректность этой спецификации невозможно.

Также nothrow спецификация move конструкторов требуется в контейнерах, чтобы гарантировать безопасное перемещение элементов.


Ок, как я написал, для разработчиков стандартной библиотеки какая-то польза может быть.

Безусловно, лучше не писать nothrow, если нет уверенности. В C++ полно вещей, которыми можно отстреливать ноги :)


И поэтому мы остаемся при промышленной разработке со старым добрым С с объектами, и не дай бог какую новую фичу применить :-)

А сам nothrow лишь возможность вынести спецификации на уровень языка (и дать возможность анализировать её компилятору)


Беда в том, что компиляторы не проверяют эти спецификации во время компиляции… или не все компиляторы, или не всегда. И хорошая идея превращается в пшик. Особенно критично при кросс-платформенной разработке с поддержкой всяких допотопных компиляторов типа IBM xlC и Sun (sorry, Oracle) CC — каждый интерпретирует стандарт по своему.
Согласен с предыдущим оратором.

Как пример неудачного поведения, кажется в MSVC 2005 (как там в более новых студиях — не знаю, не проверял) если внутри функции с throw() таки вылетает исключение то деструкторы стековых объектов созданых внутри функции не вызываются, и если где-то в деструкторе было удаление временных файлов или другие действия над долгоживущими объектами это может приводить к утечкам долгоживущих ресурсов навроде дискового пространства, что уже совсем не ок.
Статья замечательная, но примеры кода трудно читать потому что название стандартных функций и типов перемешались с названиями автора. По крайней мере это так для тех кто видит описанные в статье новшества впервые. Укажите явно пространство имен std для стандартных функций.
Мне кажется С++ эволюционирует в новый язык, я бы даже сказал мутирует. Потому что он чрезмерно усложняется плюшками которые с виду очень прикольные но в большинстве своем кроме как «смотрите как я могу» мало зачем нужны и скорее на против сделаю логику программ еще более запутанной а код менее читаемым.

Это конечно не касается thread, conditional_variable, lambda, всего того что и так уже давным давно в обиходе благодаря boost. Это именно про вот эти сумасшедшие навороты на exceptions и прочее, что пока еще мало освещено но уже в стандарте.
В простых программах никто не требует эти нововведения использовать.

А если программа достаточно сложна, чтобы в них нуждаться, то это лишь упрощает код (уменьшает объём, повышает читаемость или т.п), ну или даёт бонус в производительности, для некоторых нововведений.

Вообще, все эти нововведения весьма подробно аргументируются, по крайней мере те, что я читал. Ничего бесполезного, на мой взгляд, в C++ не попадает.
Но разрабам компиляторов и стандартных библиотек приходится несладко.
Так они всегда крайние.

Но, кстати, в плане стандартной библиотеки, многое (в gnu stl например) просто перетащено из буста, где уже и без этих нововведений в некотором виде существовало.
C++ это, по сути, три языка в одном:
1. Язык препроцессора
2. Функциональный язык, описывающий шаблоны
3. Собственно, C++
А почему авторы стандарта ввели std::exception_ptr? Почему нельзя было вместо него использовать void*? Или std::exception_ptr хранит инфу о типе исключения?
void * — это плохой вариант, сразу добавляет кучу проблем, что будет, если я скажу delete для него?
К тому же exception_ptr инкапсулирует внутри себя всю работу с исключениями, и предоставляет универсальный интерфейс по передаче исключений — вполне себе ООП-style (в отличие от того же void *)
Не могу, к сожалению, похвастаться, что было время детально разобраться со статьей, так что, может быть, банальность спрошу. Я не понял, можно при помощи новых новоротов превратить стандартные классы исключений (вон сколько только errc-«объектов» (как нынче принято называть элементы enum class?) для std::system_error понаделали) в эдакие продвинутые коды ошибок? Я имею в виду новый взгляд на старый-добрый C-шный подход, без непосредственного «бросания» и «отлавливания» исключений, спецификаций throw() (в смысле noexcept) и связанных со всей этой кухней проблем? (см. хотя бы взгляд гугла) Если можно, то было бы здорово увидеть примеры, как. А проблемы, в том числе описанные гуглом, по моему мнению связаны с тем, что компиляторы C++ не поступают с исключениями так, как это делают компиляторы Java, например — не контролируют их «отлова». Вообще никак не поддерживают, фактически, возлагая весь непростой труд по созданию exception-safe кода на программиста.
Если честно, я не совсем понял что вы имеете ввиду, errc — это обычное перечисление (enum). std::system_error — это класс, который содержит в себе код ошибки.

Есть несколько замечательных статей, о том как устроены system_error в C++ (на английском) от автора библиотеки boost.asio, если вам интересно, можете прочитать у него:
blog.think-async.com/2010/04/system-error-support-in-c0x-part-1.html
blog.think-async.com/2010/04/system-error-support-in-c0x-part-2.html
blog.think-async.com/2010/04/system-error-support-in-c0x-part-3.html
blog.think-async.com/2010/04/system-error-support-in-c0x-part-4.html
blog.think-async.com/2010/04/system-error-support-in-c0x-part-5.html
Sign up to leave a comment.

Articles

Change theme settings