2010-08-23 3 views
1

После не в состоянии поймать исключениеПоймать исключение во время выполнения

int *i; //intentionally uninitialized 

try { 
     *i = 6; 
    } 
catch (const runtime_error e) { 
     cout << "caught!" << endl; 
    } 

это на самом деле ловить ошибки во время выполнения или исключение?

+2

Кто вам сказал, что это исключение? :) Строго говоря, использование неинициализированных переменных приводит к неопределенному поведению. Даже если вы инициализировали его значением null, вы получите неопределенное поведение, когда попытаетесь разыменовать его. Неопределенное поведение означает, что все может случиться, и состояние вашей программы больше не гарантируется. (Это означает, что он ничего не может сделать, «работа», «сбой» или «да», даже исключение, хотя это, конечно же, не требуется. Windows выбрасывает исключение для ОС, но не исключение C++.) – GManNickG

+1

В C++ компилятор делает неявно добавьте проверки, чтобы убедиться, что вы глупы. Так что такие вещи не поймаются. Исключения происходят, когда разработчик явно реализует проверку и выдает исключение, когда проверка не выполняется. (компилятор НИКОГДА не сделает этого для вас). –

+0

@ GMan - потому что он говорит: «В файле myprogram.exe произошло необработанное исключение win32» – gix

ответ

4

Линия *i = 6; не выбрасывает runtime_error; это приводит к неопределенному поведению.

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

Невозможно «поймать» такую ​​ошибку как исключение в стандартном C++; вам нужно написать свой код, чтобы вы не делали подобные вещи.

1

Это не ошибка времени выполнения, это неопределенное поведение во время выполнения из-за ошибки .

Чтобы поймать его (и многие другие подобные ему), установите ваш компилятор на максимально возможный уровень предупреждения. (. Как компиляторы, вопреки комментарий Мартина, сделать чек, если вы глупы, если вы позволите им) gcc -Wall сделали бы это в данном случае:

$ g++ -Wall test.cpp 
test.cpp: In function ‘int main()’: 
test.cpp:<line>: warning: ‘i’ is used uninitialized in this function 

Лично я предпочитаю что-то вдоль этих линий:

$ CXXWARN="-Wall -Wextra -Werror -pedantic -Wno-unused-parameter \ 
     -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings \ 
     -Wmissing-declarations -Wredundant-decls -Winline" 
$ g++ $CXXWARN test.cpp 

Ваш пробег может отличаться.

+2

Я не уверен, что «ошибка времени компиляции» является хорошей (гораздо менее приемлемой) фразой для «ошибки программиста». Ошибка произошла до того, как был запущен компилятор. – Potatoswatter

+0

Все ошибки являются программистами какие-то. Ошибки времени выполнения также кодируются до запуска компилятора. Это больше о том, когда ошибка может быть * поймана *. Фраза «ошибка времени компиляции» (или «ошибка компилятора») была удобна для всех команд, над которыми я работал до сих пор, так же как и «ошибка времени соединения». – DevSolar

+0

Это ошибка времени компиляции: 'int d, d;'. Ошибка программиста - гораздо лучший термин для выражения «их вина».«Там, где возникает ошибка, это ошибка компиляции, ошибка связи, ошибка времени выполнения и т. Д., Но все они являются ошибками программиста (кроме последней, которая может быть ошибкой пользователя). – GManNickG

3

Отказ

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

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


Классы C++, полученные из exception просто удобства поощрять хорошую практику среди программистов. У них нет специальной семантики, и они ничем не отличаются от названия.

Хуже, исключения C++ не могут проходить за пределами обработчика сигналов (что на других языках будет называться «обработчиком исключений», функция, вызываемая незаконным доступом). Стандарт имеет конкретное предупреждение об этом,

A [plain old function] that could be used as a signal handler in a conforming C program does not produce undefined behavior when used as a signal handler in a C++ program. The behavior of any other function used as a signal handler in a C++ pro- gram is implementation defined.213)

213) In particular, a signal handler using exception handling is very likely to have problems

, что сказал, если вы хотите, чтобы поймать это, использовать UNIX signal средство для установки функции, которая не использует C++ функции.

#include <csignal> 
#include <cstdlib> 
#include <cstdio> 

void catch_memory(int) { 
    std::printf("caught!\n"); 
    std::abort(); 
} 

int main() { 
    std::signal(SIGSEGV, catch_memory); 

    int *i = 0; 
    *i = 6; 
} 
+0

Erm ... Я думаю, что вы 1) пропустили точку OP, которая ожидает, что произойдет исключение для чего-то, что является UB, и 2) смешение сигнала (функции, зарегистрированные с помощью 'signal()' для обработки сигналов, вызванных средой, или использования функции 'raise()') и обработчиков исключений (т.е. блоки catch). Доступ к неинициализированному указателю равен * undefined behavior *. Регистрация обработчика сигнала для SIGSEGV может или не поможет, потому что произойдет следующее: * undefined *. – DevSolar

+1

@Dev: Нет, OP ожидает, что средство исключения C++ будет d o то, что делают объекты исключения других языков. Стандарт C++ не определяет, что происходит при разыменовании «NULL» **, но другие применимые спецификации могут **. – Potatoswatter

+0

Проблема заключается в неинициализированном доступе. Решение - это предупреждения компилятора, чтобы исправить первопричину. Вы не можете написать обработчик сигналов для SIGSEGV, который позволит программе продолжать работу. Даже экономия ваших данных и чистота закрытия будет зависеть от вашего оптимизма, что ни одна из структур данных в памяти не была повреждена. Я бы назвал это «лаем неправильное дерево». – DevSolar

1

Соответствующее предложение catch выполняется, когда соответствующее исключение выбрасывается с использованием ключевого слова throw C++. Это исключения C++.

То, что вы получаете с кодом OP, вероятно, является сгенерированным системой исключением (не исключение C++), и строго это неопределенное поведение.

0

Это не исключение. Это может привести к сбою. Если вы работаете в проекте, во-первых, ознакомьтесь со своими сверстниками. Обзор кода очень полезен большую часть времени. Если нет, то вы можете поймать такие ошибки в начале цикла разработки, делая используя инструменты статического анализа кода, как Klocwork и инструменты динамического анализа кода, как Purify, Bounds Checker и т.д.

0

Microsoft создал нечто, называемое structured exceptions несколько лет назад (он же, SEH для «обработки структурированных исключений»). Хотя существует некоторое сходство между исключениями C++ и структурированными исключениями, это принципиально разные вещи. Лично я избегал SEH.

SEH позволяет, помимо прочего, распознавать, когда стек переполнен или произошло нарушение доступа к памяти. Дело в том, что в этих случаях мало что можно сделать: состояние вашей программы было безвозвратно разбито до того, как ваш обработчик получит шанс на запуск. И хотя вы не можете исправить «безвозвратно разбитый», ваш обработчик может заявить, что он это сделал (т. Е. Вы можете продолжить выполнение, даже если ваш стек был разбит).

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

Смежные вопросы