Форум программистов, компьютерный форум CyberForum.ru

Когда и где следует использовать механизм исключительных ситуаций? - C++

Восстановить пароль Регистрация
 
Ieroglif
 Аватар для Ieroglif
18 / 18 / 1
Регистрация: 23.06.2011
Сообщений: 237
31.07.2014, 20:25     Когда и где следует использовать механизм исключительных ситуаций? #1
Вечер добрый, товарищи.
Вопрос у меня в общем-то теоретический и, наверное, размытый, общий.

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

К Страуструпу посылать не надо – читал.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
31.07.2014, 20:25     Когда и где следует использовать механизм исключительных ситуаций?
Посмотрите здесь:

C++ Обработка исключительных ситуаций
Обработка исключительных ситуаций. C++
Обработки исключительных ситуаций C++
Ограничения исключительных ситуаций f(.)throw(.){} C++
C++ Обработка исключительных ситуаций
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
0x10
2426 / 1598 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
31.07.2014, 20:36     Когда и где следует использовать механизм исключительных ситуаций? #2
Цитата Сообщение от Ieroglif Посмотреть сообщение
размытый, общий
Ответ будет примерно таким же, ибо вопрос обработки ошибок сам по себе не из простых.
Цитата Сообщение от Ieroglif Посмотреть сообщение
Когда и где этот механизм использовать НЕ стоит?
Тут еще можно более-менее конкретно сказать.
1. В конструкторах - с осторожностью. Следить за тем, чтобы генерация исключения не вела к утечкам памяти.
2. В деструкторах никогда.
3. Плохой идеей будет строить на исключениях логику передачи управления при нормальном ходе выполнения программы (а-ля goto).
Цитата Сообщение от Ieroglif Посмотреть сообщение
Когда и где следует использовать механизм исключительных ситуаций?
Вспоминаем, что исключения - инструмент обработки ошибок. Следовательно, используем для информирования вызывающего кода о произошедших ошибках. Особенно удобно, когда вместе возникновения ошибки недостаточно информации для ее корректной обработки.
Цитата Сообщение от Ieroglif Посмотреть сообщение
Как лучше всего их обрабатывать?
Напрямую зависит от самого исключения. Где-то логично завершить работу приложения. Где-то - залогировать ошибку и продолжить работу.
Цитата Сообщение от Ieroglif Посмотреть сообщение
К Страуструпу посылать не надо – читал.
Но все, что сказал выше, у Страуструпа описано. Что еще добавить?
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
31.07.2014, 20:55     Когда и где следует использовать механизм исключительных ситуаций? #3
Цитата Сообщение от 0x10 Посмотреть сообщение
Вспоминаем, что исключения - инструмент обработки ошибок.
Исключения - инструмент обработки исключительных ситуаций. А исключительные ситуации не всегда являются ошибками.
Ieroglif
 Аватар для Ieroglif
18 / 18 / 1
Регистрация: 23.06.2011
Сообщений: 237
31.07.2014, 21:02  [ТС]     Когда и где следует использовать механизм исключительных ситуаций? #4
Не могли бы привести реальные или приближенные к реальным примеры? Желательно, разномастные.
0x10
2426 / 1598 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
31.07.2014, 21:25     Когда и где следует использовать механизм исключительных ситуаций? #5
Цитата Сообщение от Ieroglif Посмотреть сообщение
Не могли бы привести реальные или приближенные к реальным примеры?
1. Попытка создать вектор отрицательного размера (в общем случае - невозможность захвата ресурса).
2. Подача на вход парсеру невалидной строки.
3. Выход за границы массива.
4. Невозможность продолжения выполнения программы из-за невыполнения одного из этапов алгоритма.
Voivoid
 Аватар для Voivoid
580 / 256 / 12
Регистрация: 31.03.2013
Сообщений: 1,284
31.07.2014, 22:51     Когда и где следует использовать механизм исключительных ситуаций? #6
Цитата Сообщение от 0x10 Посмотреть сообщение
2. Подача на вход парсеру невалидной строки.
По поводу этого пункта я бы уточнил. Бросать исключение стоит только в случае, если данные на вход передаются из надежного источника от которого мы не ожидаем невалидных данных. А вот в случае если мы ожидаем данные от ненадежного источника ( например пользовательский ввод ), то имеет смысл возвращать код ошибки, потому что вероятно все равно придется сразу же проверять что там удалось напарсилось, а писать конструкции вида:

try {
parse();
}
catch ...

это не очень. Ну или по крайней мере имеет смысл делать две функции, одна бросает исключения, а другая возвращает код ошибки
Jupiter
Каратель
Эксперт C++
6543 / 3963 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
31.07.2014, 23:01     Когда и где следует использовать механизм исключительных ситуаций? #7
Цитата Сообщение от Toshkarik Посмотреть сообщение
Исключения - инструмент обработки исключительных ситуаций.
Исключения - инструмент информирования об ошибке/исключительной ситуаций. Обрабатывать или нет решает программист.
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
31.07.2014, 23:04     Когда и где следует использовать механизм исключительных ситуаций? #8
Цитата Сообщение от Voivoid Посмотреть сообщение
одна бросает исключения, а другая возвращает код ошибки
Это вроде как бустовский подход. Про всю либу не уверен, но в boost::asio активно практикуется.
Цитата Сообщение от Ieroglif Посмотреть сообщение
Когда и где следует использовать механизм исключительных ситуаций?
Там, где можно диагностировать ошибку, но ещё неясно как её следует обработать. Типичная ситуация - разработка библиотечного кода.
IGPIGP
Комп_Оратор)
 Аватар для IGPIGP
6176 / 2905 / 284
Регистрация: 04.12.2011
Сообщений: 7,735
Записей в блоге: 3
01.08.2014, 02:16     Когда и где следует использовать механизм исключительных ситуаций? #9
Ieroglif, вот довольно смешной код. Я пытался показать ситуацию, когда без генерации и обработки исключения обойтись трудновато, хотя может и заблуждаюсь.
C++
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <iostream>
#include <new>
using namespace std;
//в конструкторе последовательно выделяются два ресурса:
//это участки памяти под два массива
//моделируем ситуацию когда первый захвачен, а на втором - сбой
//аварийное окончание работы конструктора означает, что его деструктор вызван не будет
//будут только вызваны деструкторы стековых переменных (тут нет стековых переменных - классов))
//это значит что поймав такое исключение нужно проанализировать и если нужно освободить выделенную память самостоятельно 
struct SomeThingWillHappen{
int arr_size;
int *arr1;
int *arr2;
 
SomeThingWillHappen( int n){
int err_code=0;
arr_size = n;
 
//следующий блок try - catch не должен сработать, он написан подобно второму
try{
err_code  = 1;
arr1 = new int[arr_size];
err_code  = 0;
}
catch(bad_alloc& ba){
cerr << "bad_alloc caught: " << ba.what() << '\n';
//это первый ресурс и если не выделилась память, то и освобождать нечего
//передаём инфу наружу и всё
throw err_code ;//прерывание конструктора и передача исключения
}
//а этот мы запустим сами
try{
err_code = 2;
throw err_code;//имитация сбоя выделения памяти под массив arr2 
arr2 = new int[arr_size];//это не выполнится
err_code  = 0;
}
catch(int p){
cerr  <<"Bad_alloc arr2 at ctor SomeThingWillHappen( int n) "<< p << endl;
if(err_code == 2) {
//а тут понятно, что всё рухнуло и память под первый массив без нас никто не освободит
cerr <<"The memmory for arr1 succefuly allocated and will be released "<< p << endl;
//тип int - встроенный и запускать деструкторы по массиву не нужно, просто освобождаем
delete []arr1;
cerr <<"The memmory for arr1 released "<< endl;
err_code = 2;
throw err_code ;
}
system("pause");
}
for( int i = 0; i < arr_size; ++i) {
    arr1[i]=0;
    arr2[i]=i;
}
}
~SomeThingWillHappen(){
delete []arr1;
delete []arr2;
cout<<"destructor "<< endl;
system("pause");
}
};
int main()
{
    try{
SomeThingWillHappen a(4);
    }
    catch(int err_code){
        if(err_code == 1){
                  cerr <<"Bad_alloc arr1 at ctor SomeThingWillHappen( int n) " << endl;
//--------------------------------------------
////treat1
//--------------------------------------------
    }
        if(err_code == 2){
            cerr <<"Bad_alloc arr2 at ctor SomeThingWillHappen( int n) " << endl;
cerr <<"show/program)) must go on and we will treat the situation";
//--------------------------------------------
//treat2
//--------------------------------------------      
        }
    }
cin.get();
return 0 ;
}
Voivoid
 Аватар для Voivoid
580 / 256 / 12
Регистрация: 31.03.2013
Сообщений: 1,284
01.08.2014, 03:04     Когда и где следует использовать механизм исключительных ситуаций? #10
Цитата Сообщение от IGPIGP Посмотреть сообщение
вот довольно смешной код
Когда и где следует использовать механизм исключительных ситуаций?

Цитата Сообщение от Tulosba Посмотреть сообщение
Это вроде как бустовский подход
Ну, это по-моему здравомысленный подход
IGPIGP
Комп_Оратор)
 Аватар для IGPIGP
6176 / 2905 / 284
Регистрация: 04.12.2011
Сообщений: 7,735
Записей в блоге: 3
01.08.2014, 03:23     Когда и где следует использовать механизм исключительных ситуаций? #11
Цитата Сообщение от Voivoid Посмотреть сообщение
вот довольно смешной код

Еще один "умный" весчь скажу. Я не имею существенного опыта и пока, RAII напоминает мне инструкцию/манифест под лозунгом: сделай сам.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
02.08.2014, 13:35     Когда и где следует использовать механизм исключительных ситуаций?
Еще ссылки по теме:

Обработка исключительных ситуаций C++
C++ Обработка исключительных ситуаций!
Обработка исключительных ситуаций C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16845 / 5266 / 323
Регистрация: 30.03.2009
Сообщений: 14,172
Записей в блоге: 26
02.08.2014, 13:35     Когда и где следует использовать механизм исключительных ситуаций? #12
На пальцах можно сказать, что в любом культурном компиляторе поддержка исключений устроена так, что оператор try работает очень быстро, а оператор throw/catch работает очень медленно. Ещё одной особенностью исключения является многоуровневый выход из процедур.

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

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

Типа того:

C++
int main (void)
{
  /* Вызываем наш алгоритм. Если в ответ вернули true, значит всё хорошо,
   * если вернули false, значит были ошибки во входных данных */
  res = func (...);
  if (res == false)
    /* выдаём информацию об ошибке */
}
 
bool func (...)
{
  ...
  res = func1 (...);
  if (res == false)
    /* Где-то на нижних уровнях случилась ошибка, возвращаем
     * информацию об этом наверх */
    return false;
  ...
  return true;
}
 
/* Здесь по смыслу всё то же самое */
bool func1 (...)
{
  ...
  res = func2 (...);
  if (res == false)
    /* Где-то на нижних уровнях случилась ошибка, возвращаем
     * информацию об этом наверх */
    return false;
  ...
  return true;
}
 
/* Далее по такому принципу ещё несколько уровней */
 
bool func10 (int x, int y)
{
  ...
  /* И вот уже на самом низком уровне мы можем проверить,
   * что какие-то промежуточно вычисленные параметры оказываются
   * некорректными */
  if ((a + b) > 10 && (a * b) < 7 && ....)
    return false;
  ...
  return true;
}
При таком подходе мы должны постоянно отслеживать на всех уровнях возможные ошибки, произошедшие на более низких уровнях. И весь этот геморрой только ради того, чтобы в конечном итоге наверху выдать сообщение о том, что входные данные были некорректными. А может потребоваться ещё и детализация ошибки - т.е. не просто "данные корректны" или "данные некорректны", а ещё и с описанием того, что конкретно некорректно и на каком уровне проявилось, то код будет сильно перегружен обработкой ситуаций, которые, грубо говоря, являются нерабочими - т.е. информация об ошибках в боевом режиме программы будет выдаваться редко, но время на постоянную проверку на всех уровнях будет тратиться.

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

C++
int main (void)
{
  /* Вызываем наш алгоритм. Если было брошено исключение, значит
   * были ошибки во входных данных */
  try
  {
    func (...);
  } catch (...)
  {
    /* выдаём информацию об ошибке */
  }
}
 
/* Обращаем внимание на то, что нам уже не нужно возвращать
 * информацию о корректности или неорректности */
void func (...)
{
  ...
  func1 (...);
  ...
}
 
/* Здесь по смыслу всё то же самое */
void func1 (...)
{
  ...
  func2 (...);
  ...
}
 
/* Далее по такому принципу ещё несколько уровней */
 
void func10 (int x, int y)
{
  ...
  /* И вот уже на самом низком уровне мы можем проверить,
   * что какие-то промежуточно вычисленные параметры оказываются
   * некорректными. И только здесь мы генерируем исключительную
   * ситуацию, про которую более высокие уровни даже не знают,
   * а потому и не тратят время на её обработку */
  if ((a + b) > 10 && (a * b) < 7 && ....)
    trow ...;
  ...
}
Yandex
Объявления
02.08.2014, 13:35     Когда и где следует использовать механизм исключительных ситуаций?
Ответ Создать тему
Опции темы

Текущее время: 14:45. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru