Отключение исключений C ++, как я могу сделать так, чтобы любой std :: throw () был немедленно завершен? - PullRequest
32 голосов
/ 31 августа 2011

Эта программа на C ++ представляет собой скрипт CGI, у меня нет желания иметь дело с исключениями. Я предпочел бы получить незначительное повышение производительности и позволить ОС (Linux) выполнять очистку после того, как процесс завершится.

Я использую стандартную библиотеку C ++ и хочу, чтобы любая функция die была похожа на Perl: Всякий раз, когда выдается исключение. Без разматывания, или запуска любого другого кода в мой процесс.

Как работает -fno-exception? Если в моем коде вообще нет улова, и я делаю вид, что исключений не существует. но я делаю использую библиотеку std :: c ++, которую может throw ()?

Ответы [ 5 ]

62 голосов
/ 31 августа 2011

Вариант № 1: просто никогда не перехватывайте исключения.

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

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

Вариант № 2: Пропустить -fno-exceptions.

Этот флаг указывает G ++ сделать две вещи :

  1. Все обработки исключений в библиотеках STL удалены; броски заменены на abort(), звонки
  2. Стек раскручивает данные и код удаляется. Это экономит некоторое пространство кода и может незначительно упростить распределение регистров для компилятора (но я сомневаюсь, что это сильно повлияет на производительность). Примечательно, однако, что если выдается исключение, и библиотека пытается размотаться с помощью кода -fno-exceptions, она прекратит работу в этот момент, поскольку данные для размотки отсутствуют.

Это, по сути, превратит все исключения в abort() с, как вам бы хотелось. Однако обратите внимание, что вам не разрешат throw - любые действительные значения throw s или catch s в вашем коде приведут к ошибке во время компиляции.

Вариант № 3: (не переносим и не рекомендуется!) Hook __cxa_allocate_exception.

Исключения C ++ реализованы с использованием (среди прочего) функций внутренней библиотеки __cxa_allocate_exception и __cxa_throw. Вы можете реализовать библиотеку LD_PRELOAD, которая подключает эти функции к abort ():

void __cxa_allocate_exception() { abort(); }
void __cxa_throw() { abort(); }

ВНИМАНИЕ: Это ужасный взлом. Он должен работать на x86 и x86-64, но я настоятельно рекомендую против этого. Примечательно, что на самом деле это не улучшит производительность и не сэкономит место на коде, как -fno-exceptions. Однако он допускает синтаксис throw , превращая throw с в abort() с.

19 голосов
/ 31 августа 2011

-fno-exceptions превращает все броски стандартной библиотеки в вызов std::abort(). Это относится к той части, которую вы не можете изменить напрямую, остальное - вообще не использовать их в своем коде.

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

11 голосов
/ 25 ноября 2014

В случае, если кто-то наткнется на этот вопрос, я бы хотел исправить то, что @GManNickG и (https://stackoverflow.com/a/7249460/157344) и @bdonlan (https://stackoverflow.com/a/7249442/157344)) сказали в своих ответах. К сожалению, часть о "-fno -exception "удаление всего кода обработки исключений и превращение всех бросков в прерывания - это неправильно. Ну, частично неправильно. Это верно, когда вы компилируете соответствующую библиотеку (libstdc ++ v3) с этим флагом, но не так, если вы используете эту библиотеку (в виде .a или .so или .dll или чего-либо другого) в вашем собственном коде, скомпилированном с этим флагом. В последнем случае код обработки исключений в ВАШЕМ коде запрещен, но все вызовы обработки исключений внутри библиотеки остаются (потому что библиотека была скомпилирована БЕЗ этого флага с включенными исключениями), поэтому, если вы используете new, тогда ваш исполняемый файл WILL будет иметь код обработки исключений - единственное отличие состоит в том, что вы ничего не можете сделать с эти исключения с catch() (что запрещено в вашем коде), поэтому все броски в итоге заканчиваются на abort(), но только потому что никто не ловит их.

9 голосов
/ 31 августа 2011

Цитата:

Эта программа на C ++ является CGI-скриптом, я не хочу иметь дело с исключениями.

  • Тогда не надо.Просто.Исключение очень быстро попадет на вершину стека.

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

1 голос
/ 31 августа 2011

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

...