Как отловить ошибку деления на ноль в Visual Studio 2008 C ++? - PullRequest
7 голосов
/ 02 декабря 2009

Как я могу поймать ошибку деления на ноль (а не другие ошибки и получить доступ к информации об исключениях) в Visual Studio 2008 C ++?

Я пробовал это:

try {
  int j=0;
  int i= 1/j;//actually, we call a DLL here, which has divide-by-zero
} catch(std::exception& e){
  printf("%s %s\n", e.what()); 
}  catch(...){
  printf("generic exception");
}

Но это касается общего ... блока catch. Я понимаю, что специфичная для MS __try здесь может быть как-то полезна, но я бы предпочел стандарт C ++, и в любом случае у меня есть деструкторы, которые предотвращают использование __try.

УТОЧНЕНИЕ: приведенный выше код упрощен для обсуждения. На самом деле, деление на ноль - это ошибка, которая возникает глубоко в сторонней DLL, для которой у меня нет исходного кода. Ошибка зависит от параметра (дескриптор сложной структуры), который я передаю в библиотеку, но никак не очевидным образом. Итак, я хочу быть в состоянии изящно выздороветь.

Ответы [ 8 ]

9 голосов
/ 22 ноября 2011

Чтобы поймать деление на ноль исключений в Visual C ++ try-> catch (...), просто включите параметр / EHa в настройках проекта. См. Свойства проекта -> C / C ++ -> Генерация кода -> Установите для параметра Разрешить исключения C ++ значение «Да с исключениями SEH» . Вот и все!

Подробности здесь: http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx

9 голосов
/ 02 декабря 2009

C ++ не обрабатывает деление на ноль как исключение само по себе.

Цитирование Страуструпа:

"события низкого уровня, такие как арифметика переполнения и деления на ноль, являются Предполагается, что обрабатывается механизм более низкого уровня, а не исключения. Это позволяет C ++ соответствовать поведение других языков при это касается арифметики. Это также избегает проблемы, которые возникают в значительной степени конвейерные архитектуры, где события такие как деление на ноль асинхронный. "

"Дизайн и эволюция C ++" (Addison Wesley, 1994)

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

8 голосов
/ 02 декабря 2009

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

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

Сначала вам нужно установить функцию перевода Structured Exception Handling, вызвав _set_se_translator() (см. здесь ), затем вы можете проверить код, который вы передали, когда возникает исключение SEH, и выдать соответствующий C ++ исключение.

void CSEHException::Translator::trans_func(
    unsigned int code, 
    EXCEPTION_POINTERS *pPointers)
{
   switch (code)
   {
       case FLT_DIVIDE_BY_ZERO : 
          throw CMyFunkyDivideByZeroException(code, pPointers);
       break;
   }

   // general C++ SEH exception for things we don't need to handle separately....
   throw CSEHException(code, pPointers);
}

Тогда вы можете просто поймать ваш CMyFunkyDivideByZeroException() в C ++ обычным способом.

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

7 голосов
/ 02 декабря 2009

Вы можете использовать структурированную обработку исключений (используя __try и т. Д.) Или установить переводчик структурированного обработчика исключений: _set_se_translator

Обе они зависят от операционной системы.

4 голосов
/ 02 декабря 2009

Вы не можете сделать это, используя стандартный C ++, поскольку это не стандартное исключение C ++. Это структурированное исключение. Для стандартного исключения C ++ кто-то должен сделать throw exception; из кода.

3 голосов
/ 02 декабря 2009

Почему бы не проверить это раньше? Производительность будет простой для j == 0 по сравнению с переключением контекста для обработки исключений.

2 голосов
/ 02 декабря 2009

Попробуйте следующий код:

try
{ 
  const int j=0;
  if (j == 0) { throw std::exception("j was 0"); } 
  const int i= 1/j;    
}
catch(std::exception& e)
{ 
  printf("%s %s\n", e.what());  
}
catch(...)
{ 
  printf("generic exception"); 
}

Конечно, если вы делаете это без исключений, вы можете сделать:

const int j = 0;
if (j == 0)
{
  /* do something about the bad pre-condition here */
}
else
{
  const int i = 1 / j;
}

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

1 голос
/ 02 декабря 2009

Хорошим подходом было бы использование безопасных объектно-ориентированных оболочек, таких как SafeInt . Он также , кажется, интегрирован в Visual Studio 2010.

Обновление:
Если деление на ноль происходит в стороннем коде, ваш единственный вариант - SEH или что-то эквивалентное, как ответил Seb Rose

...