LINUX.ORG.RU

exceptions в C++

 ,


5

9

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

Кто-нибудь может накидать каких-нибудь технических статей на тему как следует или не следует применять эксепшены в плюсах?

UPD:
Из любопытного
почитать (стр. 32)
посмотреть

★★★★★

Последнее исправление: morse (всего исправлений: 1)

Ответ на: комментарий от tailgunner

я показал, как она выглядит в Rust без исключений. Rust использован только потому, что в нем есть готовый Result с документацией, но всё то же можно написать и на Си++.

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

eao197 ★★★★★
()
Ответ на: комментарий от RazrFalcon

Так Qt никогда не был примером реализации асинхронности для C++. Это изначально был фреймворк для GUI, причем в ранних версиях он вообще должен был работать только на главной нитке приложения. Это уже с годами Qt попытался выйти за рамки GUI и стать отдельной платформой.

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

А исключения вполне себе могут использоваться и в асинхронных фреймворках, и в многопоточных.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Это всё прекрасно, но можно примеры на практике? Или вы считает полуручной проброс исключений через furure нормальной реализацией?

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

C++14 не знаю, да. Но как я понимаю, get() блокирует вызов. А значит это обычный, синхронный вызов.

async возвращает future. У future можно вызвать get() сразу, можно в любой другой, подходящий момент. Смысл в том, что действия, переданные в async, могут выполняться асинхронно на другой нити. А get() будет лишь точкой передачи информации между текущей, и другой нитью.

Если вам нужно получить исключение из какой-то другой нити такая точка передачи вам в любом раскладе потребуется.

Так что я не понимаю, что вас не устраивает в приведенном примере. И как коды возврата здесь могут сделать ситуацию лучше.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

То есть мне нужно обернуть в try-catch std::async, а затем, где понадобится и сам get()? То есть дважды нужно ловить исключения?

Если да, то чем это лучше кодов возврата, которые будет работать точно так же.

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

То есть мне нужно обернуть в try-catch std::async, а затем, где понадобится и сам get()? То есть дважды нужно ловить исключения?

У меня ощущение, что у вас каша в голове. Try-catch вокруг std::async вам может потребоваться, если вы хотите поймать и обработать проблему создания новой рабочей нити. Try-catch вокруг future::get() может потребоваться, если хотите поймать проблему, переданную из рабочей нити.

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

Тем не менее, данный пример показывает, что многопоточность и исключения вполне себе сочетаются.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Смысл в том, что...

std::async каждый раз создает новый поток. Крестодети хотели что-то показать, но как всегда облажались по полной. Хотя вот это

Тем не менее, данный пример показывает, что многопоточность и исключения вполне себе сочетаются.

вполне себе показали. Правда опять стыдливо умолчали о двукратном увеличении «стоимости» таких исключений.

Ну и чисто из любопытства: будет ли это работать, если для исключения не определено копирующего конструктора?

kawaii_neko ★★★★
()
Ответ на: комментарий от intelfx

Няша, какой же ты максималист. Как таким быть можно, а?

anonymous
()
Ответ на: комментарий от eao197

Ага, значит нет. Тебе бы следовало научиться strace использовать - узнал бы много нового о реализации многих плюсовых библиотек.

kawaii_neko ★★★★
()
Ответ на: комментарий от annulen

Во-первых, им это не помогло: современный clang (имхо, это основной и самый впжный подпроект llvm) компиляет релиз за время, сравнимое с GCC. Оптимизации c++ - они так просто не даются. Подход «давайте просто не будем использовать фичу языка и тогда у нас все будет летать» тут не работает

Во-вторых, это не аргумент в споре. Да, исключения не бесплатны. Но Профит от них очевиден. А стоимость их преувеличена на мейнстримных платформах. Llvm, как программа, должен запускаться на таких жопах, которыми многие другие языки даже не имеют таргета в компиляторе/VM/интерпретаторе.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

Llvm, как программа, должен запускаться на таких жопах, которыми многие другие языки даже не имеют таргета в компиляторе/VM/интерпретаторе.

(Это аргумент об охвате платформ, где должны запускаться трансляторы фронтэндов и бекендов llvm. Я понимаю, что это не VM; сообщение получилось несколько двусмысленным)

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от eao197

У меня ощущение, что у вас каша в голове.

В чём? Да, создание и получение результата может вернуть ошибку. Если я хочу это отловить - оборачиваю в try-catch и проверяю. В двух местах. Что я делаю с кодами возврата? Правильно - тоже самое. Только исключения нужно вручную пробрасывать, ибо из коробки они не потокобезопасные (поправьте меня если это не так). В итоге больше мороки.

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

Наглое 4.2

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

В чём?

В том, что вы сами не знаете, чего хотите. Сначала говорите про невозможность использовать исключения в многопоточном коде, когда вам это показывают, то начинаете считать невесть откуда взявшиеся try-catch, говорить про потоконебезопасность исключений и пр.

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

Наглое 4.2

Вам же не составит труда показать, как просто так проигнорировать исключение в C++, не правда ли?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

невозможность использовать исключения в многопоточном коде

Я не говорил, что это не возможно, я говорил, что это не удобно.

как просто так проигнорировать исключение

Не написать нужный catch в нужном месте?

и лучше Qt в мире C++ ничего не видели

А что-то есть? boost не предлагать.

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Не написать нужный catch в нужном месте?

Вы всерьез не понимаете, что такое «проигнорировать»?

А что-то есть?

Смотря для чего. Ну и boost он очень разный. Покажите что-то лучше Boost.MultiIndex в своем классе.

eao197 ★★★★★
()
Ответ на: комментарий от Deleted

Llvm, как программа, должен запускаться на таких жопах, которыми многие другие языки даже не имеют таргета в компиляторе

И что это за экзотическкие платформы? Приведи пример.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Но это правда. Достаточно собрать hello world для теста.

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Я более чем уверен, что это можно трактовать по разному.

У меня трактовка простая. Вот игнорирование ошибки:

FILE * f = fopen("wrong_name.txt", "rb");
fread(buf, 1, buf_size, f);
А вот если бы fopen в случае ошибки порождал исключение, то до fread дело бы не дошло. Это и означает, что ошибку нельзя проигнорировать.

eao197 ★★★★★
()
Ответ на: комментарий от tailgunner

Ну вот я лично видел как отсутствие -fno-exceptions блокирует оптимизацию кода. Асм смотрел в обоих случаях

annulen ★★★★★
()
Последнее исправление: annulen (всего исправлений: 1)
Ответ на: комментарий от annulen

Да и не LLVM'ом единым, например GCC, WebKit, проекты Mozilla и Google тоже не используют исключения

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

Правило кажется бессмысленным анахронизмом.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Если не ошибаюсь, rtti хранит имена всех типов.

RazrFalcon ★★★★★
()
Ответ на: комментарий от tailgunner

Да. Чем больше типов - тем больше весит. Где-то находил инфу, что на 10-15% меньше без исключений.

Я так свой Qt софт собираю. Всё равно там нет исключений.

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

«Где-то находил» - это несерьезно.

Я так свой Qt софт собираю. Всё равно там нет исключений.

Можешь собрать его с исключениями и без, и опубликовать размеры стрипнутых бинарей?

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Проект на 20к строк. Qt. После strip.

Без исключений* - 1.3M (1260784). С исключениями - 1.6M(1613248).

* QMAKE_CXXFLAGS_RELEASE += -fno-exceptions -fno-rtti

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Спасибо. Но меня больше интересует _только_ без исключений. Понятно, что таблицы RTTI для большой библиотеки вроде Qt будут большими.

tailgunner ★★★★★
()
Ответ на: комментарий от RazrFalcon

Вот тут не проигнорируешь.

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

eao197 ★★★★★
()
Ответ на: комментарий от tailgunner

Ладно, это была неправильная догадка. http://llvm.org/docs/GettingStarted.html#hardware

Но я уверен, 100 пудово, когда это правило придумывали, это было одной из причин :) так люди устроены. И в те времена картина поддерживаемых платформ была другой :)

Ну значит остается только одна объективная причина - хотели максимально сыграть на производительности, и вклад от исключений посчитали неприемлемым.

Deleted
()
Ответ на: комментарий от eao197

Вы уже потеряли нить разговора. Я сразу сказал, что в плюсах лучше исключения, ибо нормальный аналог Result не сделать. Потом было пару вариантов, но я их еще не тестил. Может изменю своё мнение.

RazrFalcon ★★★★★
()
Последнее исправление: RazrFalcon (всего исправлений: 1)
Ответ на: комментарий от Davidov

«slow» тут не причём. Исключения в плюсах нельзя кидать из деструктора. Но сильно желательно кидать из конструктора. В то же время, из конструктора нужно кидать аккуратно, чтобы не кинуть из статического объекта при инициализации. Кроме того, нельзя, чтобы исключения покидали свой .so, так как вызывающий код их не поймает.

Наконец, в средах типа Qt исключения почти никогда не нужны, ибо концепция сигнал-слот является надмножеством концепции исключений. Кроме тех случаев, когда происходит исключение по исчерпанию оперативной памяти.

Ну как-то так.

next_time ★★★★★
()
Ответ на: комментарий от RazrFalcon

Потом было пару вариантов, но я их еще не тестил. Может изменю своё мнение.

ваше экспертное заключение с нетерпением ждет все сообщество C++ в мире!

anonymous
()
Ответ на: комментарий от RazrFalcon

Всё, что можно выразить исключениями, можно выразить qt-сигналами, но не наоборот. Представьте, у вас при ошибке кидается не исключения, а просто сигнал. Чем плохо?

next_time ★★★★★
()
Ответ на: комментарий от next_time

Всё, что можно выразить исключениями, можно выразить qt-сигналами, но не наоборот. Представьте, у вас при ошибке кидается не исключения, а просто сигнал. Чем плохо?

Покажите, плз, как пример с открытием файла отсюда переписать на сигналах/слотах.

eao197 ★★★★★
()
Ответ на: комментарий от next_time

Всё, что можно выразить исключениями, можно выразить qt-сигналами, но не наоборот

вот он! человек глупее RazrFalcon!

поделитесь секретом успеха с публикой, вы сделали невозможное! лоботомия? засунули карандаш в нос на полную длину? как? каааак?

anonymous
()

джавы, где обработка исключительных ситуаций с помощью эксепшенов - это нормально и хорошо

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

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

жабовский же подход где «обрабатывают» ошибки на исключениях это такая устоявшаяся рукожопокодерская практика, аналогичная привычке плодить на каждое действие новый поток, а потом трахаться с синхронизацией

i36_zubov
()
Ответ на: комментарий от deadskif

Ну попробуйте накидать что-то подобное. Может желание задавать такие вопросы само отпадет.

Только оставайтесь в рамках C++, пожалуйста.

eao197 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.