LINUX.ORG.RU

C++ exceptions: быть или не быть

 ,


5

7

Привет!
На работе спор плюсовиков: юзать или не юзать исключения от слова совсем.

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


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

Это приблизительные значения с возвращением красивого стэк трейса, конечно же

Какой глубины - миллион? Или таблица символов подтягивалась с диска? Иначе такого времени тупо не может быть.

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

Присутствие Result в сигнатуре, как минимум, сигнализирует, что функция не чистая.

К чистоте функции Result не имеет никакого отношения.

А паттерн матчинг позволяет свести проверки Result к по сути линейному коду, а не ветвлению.

С какой же это стати?

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

Какой глубины - миллион? Или таблица символов подтягивалась с диска? Иначе такого времени тупо не может быть.

Попробуй собраться с libunwind из llvm, ты узнаешь много нового про красивые трейсы ;) Глубина может быть до сотни доходила(короутины и все такое).

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

Какой глубины - миллион? Или таблица символов подтягивалась с диска? Иначе такого времени тупо не может быть.

Попробуй собраться с libunwind из llvm, ты узнаешь много нового про красивые трейсы ;)

Я собираю с libbacktrace.

Глубина может быть до сотни доходила(короутины и все такое).

Глубина стека 100, время на раскрутку - 300мс, то есть 3мс на кадр? То ли в LLVM феноменально тормознутые исключения, то ли в замеряемом случае при раскрутке печаталось вообще всё, и потраченное на печать время входит в эти 300мс.

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

Исключения позволяют писать, не обрабатывая ошибок вообще нигде (кроме catch(...) в main), чем люди и пользуются.

Так это же замечательно.

С Result по крайней мере видно, где ты отказался обрабатывать ошибку.

Зачем это должно быть видно? С исключениями это также видно - где нет try - там и «отказался».

Этого мусора меньше, чем try-catch.

Я понял, вы наверное думаете что исключения это try/catch вокруг каждой функции как if'ы в C. Я вас огорчу, это не так, это как раз «не обрабатывание ошибок вообще нигде», которого вы почему-то боитесь. Ошибка должна быть обработана там где на неё может быть какая-то реакция. Это может быть ретрай или выдача ошибки пользователю. Должно быть очевидно что таких мест довольно мало. В какой-нибудь консольной утилите это место ровно одно, и как раз в main, и в него будет обёрнута вся логика. В web сервере в try будет обёрнута вся обработка запроса. В низкоуровневом коде не будет и не должно быть ни try и ни какой-то другой явной реакции на ошибки - ей там быть незачем и её там быть не должно.

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

Но если мне нужно выполнять кучу мелкий заданий, типа GUI, то нажатие каждой кнопки нужно оборачивать в catch(...)

В переводе на человеческий язык это означает: «но если мне нужно взаимодействовать кодом, который из-за древности своей не поддерживает исключения...»

так как я не знаю какие исключения прилетят и прилетят ли вообще (да, я про бесполезный noexcept)

Спрашивать вас о том, зачем вам это знать, как подсказывает опыт вытягивания из вас осмысленной информации, бесполезно. Сим сакральным знанием вы не поделитесь.

Про многопоточный код вообще молчу.

Вы бы вообще про C++ молчали бы. Так ведь нет, все время вас тянет отжечь глаголом.

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

Исключения позволяют писать, не обрабатывая ошибок вообще нигде (кроме catch(...) в main), чем люди и пользуются.

Так это же замечательно.

Это замечательно, пока обработка ошибок сводится к «напечатали в stderr».

Я понял, вы наверное думаете что исключения это try/catch вокруг каждой функции как if'ы в C. Я вас огорчу, это не так, это как раз «не обрабатывание ошибок вообще нигде», которого вы почему-то боитесь.

Не угадал ни разу.

В низкоуровневом коде не будет и не должно быть ни try и ни какой-то другой явной реакции на ошибки - ей там быть незачем и её там быть не должно.

Ну да, ну да. А потом процессы в состоянии D невозможно убить.

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

Имеет самое прямое.

Обсуждается то, что с Result в каждом вызове функции, которая может завершиться неудачей требуется лишний код. Объясни какое к этому имеет отношение разница между ?, матчингом и unwrap. Это всё лишний код.

Обработка ошибок не лишнее действие. ? никто не отменял.

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

Кто бы говорил.

Всё что я утверждал я подкрепил аргументами.

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

Это замечательно, пока обработка ошибок сводится к «напечатали в stderr».

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

Ну да, ну да. А потом процессы в состоянии D невозможно убить.

И как же D связан с Result и исключениями?

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

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

Глубокомысленно.

А потом процессы в состоянии D невозможно убить.

И как же D связан с Result и исключениями?

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

slovazap> В низкоуровневом коде не будет и не должно быть ни try и ни какой-то другой явной реакции на ошибки - ей там быть незачем и её там быть не должно.

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

К чистоте функции Result не имеет никакого отношения.

В смысле не имеет? Result говорит, что функция взаимодействует с реальным миром. Это ли не определение не-чистой функции?

А паттерн матчинг позволяет свести проверки Result к по сути линейному коду, а не ветвлению.

С какой же это стати?

Я не про машкод, а текст программы.

Virtuos86 ★★★★★
()
Ответ на: комментарий от I-Love-Microsoft

Ничего не делаю. Пользуюсь адекватными фреймворками без экзепшенов. QFile если не открылся - скажет false. Если попытаться прочитать данные из неоткрытого файла - read даст ноль вот и всё. Вот как надо правильно жить :)

А зачем тебе С++? Тебе С достаточно.

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

Есличо, из стандартной библиотеки исключения будут убирать. Если не все то большинство.

Пруф?

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

Это ли не определение не-чистой функции?

Нет, не это, почитайте определение хотя бы на википедии..

В смысле не имеет? Result говорит, что функция взаимодействует с реальным миром.

Не говорит. Чистая функция (в классическом определении) может возвращать Result с Err в зависимости только от своих аргументов. И наоборот, есть функции с состоянием, которые могут или не могут возвращать Err. И есть функции взаимодействующие с реальным миром которые могут или не могут возвращать Err. Result никак не связан ни с чистотой, ни с состоянием, ни с взаимодействием.

Я не про машкод, а текст программы.

Ничего не изменилось. В коде это также будет ветвление в самом явном виде.

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

OK, прямой зависимости между чистотой и Result нет, только косвенная вероятность.

Ничего не изменилось. В коде это также будет ветвление в самом явном виде.

Нет.

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

Хорошо: сколько?

Это сильно зависит от того сколько у тебя кэч блоков и какова глубина стэка, ресровятся ли дальше эксепшены итд. В целом от 250 мс для libgcc, от 300 мс для libunwind от hp и где-то от 700 мс для libunwind llvm.

Цифры ни о чем. Ни описания что за код, ни сколько exception'ов, какой CPU, интервал замера... С таким же успехом можно написать «от 3750ms».

Когда это может стать bottleneck'ом?

Когда у тебя много экспешенов?

Если ты пишешь логику на исключениях, то ты ССЗБ.
В остальных случаях это bottle-neck'ом никогда не будет. Хотя бы потому, что при нормальной логике исключения вызываются относительно редко, а для базового пути exception'ы быстрее, чем if'ы.

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

быстрее, чем if'ы.

а кейсы-то, кейсы-то ещё можно использовать? или там та же проблема?

anonymous
()

Насколько я в курсе, проблема не только в скорости исключений, нужно ещё писать код, который будет готов к тому, что он может прерваться где угодно. Гугл в своём Style Guide (https://google.github.io/styleguide/cppguide.html) отказался от исключений по этой причине.

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

Етить-колотить, когда же те эрудиты, которые ссылаются на гугловский гайдлайн, дочитают этот самый гайдлайн до вот этого абзаца:

On their face, the benefits of using exceptions outweigh the costs, especially in new projects. However, for existing code, the introduction of exceptions has implications on all dependent code. If exceptions can be propagated beyond a new project, it also becomes problematic to integrate the new project into existing exception-free code. Because most existing C++ code at Google is not prepared to deal with exceptions, it is comparatively difficult to adopt new code that generates exceptions.

Специально для тех, кто этот абзац даже здесь осилить не сможет: у Гугла изначально исключения не использовались, а когда опомнились, то решили, что дешевле не начинать использовать.

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

Ну попробуй объяснить в чём, по-твоему, принципиальная разница в наличии ветвления между

match res {
    Err(err) => handle_err(err),
    Ok(val) => handle_ok(val),
}

и

if (res.is_err())
    handle_err(res.get_err());
else if (res.is_ok())
    handle_ok(res.get_val());
slovazap ★★★★★
()
Последнее исправление: slovazap (всего исправлений: 1)
Ответ на: комментарий от Kroz

Спасибо, Капитан. Ты развеял все мои сомнения по поводу эксепшенов.

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

Он самый тормозной и самый красивый, да

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

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

Ну попробуй объяснить в чём, по-твоему, принципиальная разница в наличии ветвления между

match res

и

if (res.is_err())

else if (res.is_ok())

В наличии ветвлений - никакой, всё соптимизируется до одного и того же кода. Но разница не в инструкциях на ветвление (кого они вообще интересую в век OoO-процессоров), а в том, что в match гораздо труднее (или даже вообще невозможно) сделать ошибку.

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

Насколько я в курсе, проблема не только в скорости исключений, нужно ещё писать код, который будет готов к тому, что он может прерваться где угодно

С RAII это даже специально делать не надо, всё само получается.

Гугл в своём Style Guide (https://google.github.io/styleguide/cppguide.html) отказался от исключений по этой причине.

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

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

В наличии ветвлений - никакой, всё соптимизируется до одного и того же кода

А товарищ вот утверждает что разница есть, и пытается выкрутиться что он якобы даже не про машинный код.

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

пытается выкрутиться что он якобы даже не про машинный код.

Я тоже не про машинный код.

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

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

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

может у него красивый с цветами и графикой бектрейс

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

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

И как вы предлагаете обрабатывать исключения в GUI?

Спрашивать вас о том, зачем вам это знать
При этом желательно показать пользователю сообщение сложнее «неизвестное исключение».

?

Вы бы вообще про C++ молчали бы.

Как всегда безапелляционно.

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

Это всё лишний код.

Что именно? Значок ? или то, во что он разворачивается? Если второе, то исключения тоже раздувают бинарь.

Всё что я утверждал я подкрепил аргументами.

Это вкусовщина, а не аргументы.

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

Как будто С и С++ отличаются только лишь наличием исключений.

RazrFalcon ★★★★★
()
Ответ на: комментарий от slovazap
type Result<T> = std::result::Result<T, ()>;

fn foo(x: bool) -> Result<i32> {
    bar(bazz(x))
}

fn bar(x: Result<i32>) -> Result<i32> {
    x
}

fn bazz(x: bool) -> Result<i32> {
    // явное ветвление только в одном месте
    match x {
        true => Ok(1),
        false => Err(()),
    }
}

fn main() {
    println!("Result: {:?}", foo(true));
    println!("Result: {:?}", foo(false));
}

http://play.rust-lang.org/?gist=9082d99ff6d2dbed2c6174ce113cef55&version=...

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

я то пробовал, у меня проблем нет, поэтому и спрашиваю какие у вас проблемы с учетом того что ваш язык вообще раст

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

вы понимаете значение слова «проблема» ?
у меня проблем с иcключениями в гуи нет
поэтому что бы диалог состоялся, нужна проблема
а вы ее скрываете

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

Шта?


так вы на два лагеря троль, в одном православный цепепешник, в другом расист ?
а когда шапку бурку обычно меняете ?

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

Специально для тех, кто этот абзац даже здесь осилить не сможет: у Гугла изначально исключения не использовались, а когда опомнились, то решили, что дешевле не начинать использовать.

При этом, например, absl уже пишется с поддержкой исключений (и у них есть какой-то инструмент для тестирования корректности кода с точки зрения исключений, которым даже несколько багов в стандарте/стандартной библиотеке поймали): https://github.com/abseil/abseil-cpp/issues/37. Так что есть надежда, что через десяток лет этот пункт пропадёт.

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

Я вообще-то оба языка активно использую. И кода на С++ у меня в разы больше, чем на Rust.

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

Ну вот нажимает пользователь кнопку. Это приводит к вызову определенной функции. В этой функции нужно выполнить определённые действия, который могут бросить исключение. Где мне обрабатывать исключение?

RazrFalcon ★★★★★
()

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

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

В сравнении с if (...), когда исключения/ошибки не возникает, то код с исключениями быстрее. В случае возникновения исключения/ошибки, код с исключениями медленнее.

Но чтобы бросить исключение, надо сделать if (...), так что тут мерято тогда?

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

deep-purple ★★★★★
()
Ответ на: комментарий от I-Love-Microsoft

QFile если не открылся - скажет false

Да, а ты делаешь паровоз вложенных возвратов. Проходили уже. Спасибо.

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