Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
Коллеги! Давайте обсудим C++ exceptions. 1) Best practices. 2) Антипаттерны. В рамках продолжения Идеология С++ и warnings ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 17:59 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
Исключения, как уже отмечали, появились не в плюсах и появились они для того, чтобы отделить "рабочий поток исполнения" и "обработку ошибок". Можно имитировать через setjump/longjump, но возникают проблемы с деструкторами объектов: всё, что компилятор трудолюбиво заготовил на стеке - идёт лесом. Можно имитировать "циклом с прерыванием" - будет минимальное "замусоривание" кода тривиальными вставками вида: Код: sql 1. Насколько я понимаю, в обоих вариантах будут проблемы с многопоточным кодом. "Как-то так". ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 18:20 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
Добавлю еще пункт. 3) Неперехваченный exception в конструкторе. Будет-ли создан объект? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 18:46 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
"Выполнение кода остановится в точке генерации исключения. Деструкторы не вызываются, если конструктор не отработал до конца" - не дословная цитата Скотта Мейерса. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 18:49 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
За что я не люблю исключения: 99.(9)% людей не умеют их использовать. В большинстве учебников исключения объяснены на примерах типа такого: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. Все мило и замечательно, четко, понятно и вообще красиво. Но после этого, в реальном коде люди постоянно пишут текст типа: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. И потом начинают кручиниться: "А как узнать почему именно упали? Мы не смогли найти файл? Не смогли прочитать его? Не смогли записать? Или произошло что-то еще не связанное с файлом?" Вот вам конкретный пример такого человеческого поведения: 17179694 . Дмитрий застрял именно на том, что у него есть несколько однотипных операций, все они способны выкинуть одно и то-же исключение. Но ему надо понять какая конкретно операция упала, а он не может этого сделать. Почему не может, хотя метод решения лежит на поверхности? Потому что он привык что в try{}catch блоке находится несколько операторов. И обработка ошибок ВСЕГДА идет по окончанию блока. Ну вот привык человек и все. Как дополнительный пример этой же самой проблемы, можно ткнуть пальцем в статью Завалишина опубликованную аж в 97-ом, и до сих пор еще читаемую: 17185154 . В статье много эмоций, но... Берем самое начало статьи "Как это делают в С++". Завалишин предлагает два примера (номера 4 и 5) в качестве иллюстрации как удобно с исключениями и как не удобно без них. И на первый взгляд он прав - код с исключениями короче... но.... если чуть-чуть приглядеться, то видно что примеры разные и решают разные задачи по разным алгоритмам. Причем работа надо ошибками в пятом примере более качественная чем в четвертом примере. Вторая гигантская проблема исключений это то что их можно перекидывать на уровень выше: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. А теперь попробуйте сказать, какой из вызовов foo1() упал. Тот который был вызван напрямую из foo3() или тот который вызывался через посредничество foo2()? Примеров подобных вопросов на форуме я сейчас с ходу не нашел, но все кто занимается поддержкой существующего софта встречались с этой проблемой. Вы можете спросить: ну так а что мешает разрезать пример с обновлением файла на три try{}catch блока? И что мешает написать foo2() во втором примере так чтобы он сам ловил исключение в foo1() и кидал в свою очередь более информативное исключение? Ответ: ничего не мешает кроме привычек. Человек привыкший к работе с кодами возврата всегда думает в каком логическом блоке он находится. И с самого начала обработает ошибку по месту ее возникновения. При работе с кодами возврата мы вынуждены думать где мы сейчас находимся и что надо делать в случае потенциальной проблемы. А у человека привыкшего к исключениям такого навыка просто нет. В учебнике сказано что обработку ошибок можно делать в самом конце? Значит мы всегда будем ее делать в самом конце и не важно правильно ли это. Да, используя исключения можно написать хорошую и качественную программу. Теоретически это возможно. Но к сожалению, в реальности это практически не встречается. Для правильной работы с исключениями надо понимать что они работают не так как думает человек. Не просто знать, а понимать, чувствовать, принять как дыхание. Мы, люди, когда пишем в программе: Код: plaintext 1. 2. 3. 4. 5. 6. 7. Мысленно проговариваем про себя: "вызвали call1(), если упали идем в блок catch, потом вызвали call2(), если упали идем в блок catch, и наконец вызвали call3(), если упали идем в блок catch." И мы думаем что это все именно так и происходит. Но к сожалению, это вовсе не так. На самом деле этот код означает "Если мы попали в catch, значит какой-то кусок, какой-то из функций не отработал. Причем мы не знаем конкретно какая из функций call1, call2 или call3 не доработала до конца и в какой степени эта функция не отработала до конца". Если вы сумеете перестроить свое сознание на правильное понимание что такое исключение - вы сможете писать хорошие программы с ними. Практика показывает что таких людей на свете единицы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 19:55 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
White Owl, в данном примере хотелось-бы чтобы компиллятор сделал Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. Или что-то в этом роде. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 20:34 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
White OwlЗа что я не люблю исключения: 99.(9)% людей не умеют их использовать. Ггггггг Гигантская проблема исключений то что эти 99.9% считают что уж они то умеют. И потом по форумам рассказывают небылицы. Например про то, что то, ради чего исключения и были придуманы, и без чего они вообще никому не нужны, оказывается - это гиганская проблема: White OwlВторая гигантская проблема исключений это то что их можно перекидывать на уровень выше Еще раз повторю то что писал уже в том топике другими словами. Чем дальше уровень вложенности где ловятся исключения от уровня где они бросаются, тем правильнее исключения используются. И верхним уровням никогда не требуется знать где конкретно произошло исключение нижнего уровня. Если вам требуется - то у вас дизайн программы сделан через одно место. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 20:59 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
mayton Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. Вот это пример антипаттерна. Когда ловля исключений используется только для отладки. Для этого вообще то логирование существует. Данный код должен выглядеть так: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. Никаких try catch тут не надо вообще. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 21:06 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
В исключениях есть минусы: 1. нижний уроверь имеет больше конкретики о причине исключения. 2. освобождение ресурсов ОС. Хотя если обернуть все в классы, то решаемо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 21:09 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
Dima T2. освобождение ресурсов ОС. Хотя если обернуть все в классы, то решаемо. Если используются исключения всегда должно применяться RAII. Иначе смысла в них нет. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 21:36 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
Anatoly MoskovskyВот это пример антипаттерна. Когда ловля исключений используется только для отладки. Для этого вообще то логирование существует. Данный код должен выглядеть так: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. Никаких try catch тут не надо вообще. Ну вроде как по пункту (2) отметились. Повестка двигается. А теперь вопрос. Что это за объект такой logger? И зачем он мне нужен? Я не хочу никаких логгеров. Мне выводить - некуда. Нет у меня файловой системы. Вот такие вот условия. Может быть такое быть? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 22:39 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
2 Белый Сова. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. Ну... если-б каждый метод подсистемы IO бросал свой уникальный expeption. Код: plaintext 1. 2. 3. 4. 5. То мы могли-бы ловить в коде некий общий тип исключений и позиционироваться более конкретно. Но опять-же... если в блоке try мы работаем с двумя файлами.... :( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 23:05 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
maytonWhite Owl, в данном примере хотелось-бы чтобы компиллятор сделал Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. Или что-то в этом роде.Нет. Этого не достаточно. Падение произошло внутри одной из функций. Мало знать какая функция упала, надо еще знать почему она упала. Это более-менее хорошо сделано в java, где исключение автоматоматически собирает полный стек вызовов при передаче на верхние уровни. Там уже действительно можно пройти по списку и действительно найти истинный источник ошибки. В С++ это можно сделать и вручную конечно, но это надо делать. В жизни с кодами возврата конечно все намного труднее потому что там вообще все надо делать вручную. Но в этом и плюс - ты всегда знаешь что если надо ошибку передать наверх, ты будешь ее передавать наверх. Сам. Вручную. Перед этим обдумав. А не просто махнув рукой: "Здесь мы работаем с фигулькой которая может глюкнуть. Но мне лениво сейчас разбираться как это обработать. Выкину исключение, пусть мой коллега который будет работать с этой функцией разбирается". Тот перекидывает исключение выше, а в итоге оно если и обрабатывается, то уже никому не известно откуда оно родилось. Повторюсь еще раз. С исключениями можно работать, но надо думать что делаешь. Учебники (и форумные гуру) представляют исключение как очень простую и удобную штуку. Как результат: люди используя исключения не пытаются видеть полную картину своей программы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 23:15 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
Anatoly MoskovskyWhite OwlЗа что я не люблю исключения: 99.(9)% людей не умеют их использовать. Ггггггг Анатолий, прочитайте мой пост еще раз. И на этот раз не по диагонали, и не ограничиваясь примерами. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 23:17 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
mayton2 Белый Сова. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. Ну... если-б каждый метод подсистемы IO бросал свой уникальный expeption. Код: plaintext 1. 2. 3. 4. 5. То мы могли-бы ловить в коде некий общий тип исключений и позиционироваться более конкретно. Но опять-же... если в блоке try мы работаем с двумя файлами.... :( Вот именно потому что мы работаем с файлам два раза (или с двумя файлами) и еще с неким алгоритмом обрабатывающим строку, данный код по хорошему должен выглядеть так: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. Но... Вот наглядный пример, ты сам. С++ знаешь, с исключениями работать умеешь, но пошел по пути создания множества дополнительных исключений. Почему? Что тебе помешало разбить алгоритм на блоки и сделать для каждого свой обработчик? Я со своей привычкой к кодам возврата обошелся одним дополнительным, ты сделал пять дополнительных и сам испугался. Почему? Потому что привык что все исключения обрабатываются в конце. Так в учебниках пишут... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 23:32 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
Тогда делаем макрос Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. Хотя возможно до меня этот макрос (класс или шаблон или функцию) уже где-то делали. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.01.2015, 23:41 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
maytonТогда делаем макросНафиг-нафиг. Наша цель же упростить программирование и не потерять гибкости. Макрос, особенно такой, это усложнение. Так что нафиг-нафиг. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.01.2015, 00:48 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
maytonА теперь вопрос. Что это за объект такой logger? И зачем он мне нужен? Я не хочу никаких логгеров. Мне выводить - некуда. Нет у меня файловой системы. Вот такие вот условия. Ну тогда вам сначала надо применить это условие по отношению к вашей функции message() ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.01.2015, 07:35 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
White OwlАнатолий, прочитайте мой пост еще раз. И на этот раз не по диагонали, и не ограничиваясь примерами. Ну вот читаю еще раз. White OwlНо ему надо понять какая конкретно операция упала, а он не может этого сделать. Это нужно программисту расследующему баги. И это решается логированием, как я выше привел. А вот зачем самой функции в процессе выполнения это знать? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.01.2015, 07:53 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
White OwlЗа что я не люблю исключения: 99.(9)% людей не умеют их использовать. ... Практика показывает что таких людей на свете единицы.прекрасный спич, но практика показывает, что 99.(9)% вообще не обрабатывают ошибки времени выполнения. Коды возврата технично игнорируются и программа падает в непредсказуемом месте из-за деления на 0 или по защите памяти, к примеру. В большой степени это происходит из-за того, что довольно нудно обрабатывать после каждого вызова этот самый код ошибки. catch в конце блока хотя бы гарантирует, что сломалось где-то здесь, и дальше этого места ошибка не распространится. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.01.2015, 09:43 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
Anatoly MoskovskyWhite OwlНо ему надо понять какая конкретно операция упала, а он не может этого сделать. Это нужно программисту расследующему баги. И это решается логированием, как я выше привел. А вот зачем самой функции в процессе выполнения это знать?+1. Золотые слова )) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.01.2015, 09:44 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
Исключения в C++ состоитят из двух частей 1.механизм 2.имплементация в стандартной библиотеке. Первое сделано хорошо, второе нет. Можно добавить логирование backtrace() и __LINE__ при генерировании своих исключений. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.01.2015, 10:24 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
egorychAnatoly Moskovskyпропущено... Это нужно программисту расследующему баги. И это решается логированием, как я выше привел. А вот зачем самой функции в процессе выполнения это знать?+1. Золотые слова )) выдать одну ошибку кастомеру "Ваша программа неработает" ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.01.2015, 10:26 |
|
||
|
C++ exceptions. Best practices.
|
|||
|---|---|---|---|
|
#18+
OoCcegorychпропущено... +1. Золотые слова )) выдать одну ошибку кастомеру "Ваша программа неработает" ? Уже говорили выше. Я-бы добавил что стоит различать просто факт возникновения ошибки (например SocketException). После этого, метод выболняющий к примеру softwareupdate молча уходит в ожидание. Мало-ли что там с сетью. WiFi отвалился. И второй вариант - это как сказано выше для анализа ошибок разработчиком. В этом варианте я не просто хотел-бы получить __LINE__ где "стрельнуло" но и "посмертный снимок" стека. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.01.2015, 10:31 |
|
||
|
|

start [/forum/topic.php?fid=57&msg=38865863&tid=2019127]: |
0ms |
get settings: |
12ms |
get forum list: |
15ms |
check forum access: |
5ms |
check topic access: |
5ms |
track hit: |
59ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
64ms |
get tp. blocked users: |
2ms |
| others: | 298ms |
| total: | 475ms |

| 0 / 0 |
