В чем разница между exit () и abort ()?


Ответы:


116

abort()выходит из вашей программы без вызова функций, зарегистрированных с использованием atexit()первой, и без предварительного вызова деструкторов объектов. exit()делает оба перед выходом из программы. Однако он не вызывает деструкторы для автоматических объектов. Так

A a;
void test() { 
    static A b;
    A c;
    exit(0);
}

Будет разрушать aи bправильно, но не будет вызывать деструкторы c. abort()не будет вызывать деструкторы ни для одного из объектов. Поскольку это прискорбно, Стандарт C ++ описывает альтернативный механизм, который обеспечивает правильное завершение:

Все объекты с автоматической продолжительностью хранения уничтожаются в программе, функция которой main()не содержит автоматических объектов и выполняет вызов exit(). Управление может быть передано напрямую такому main()объекту, выбрасывая исключение, которое перехватывается main().

struct exit_exception { 
   int c; 
   exit_exception(int c):c(c) { } 
};

int main() {
    try {
        // put all code in here
    } catch(exit_exception& e) {
        exit(e.c);
    }
}

Вместо звонка exit()используйте этот код throw exit_exception(exit_code);.


2
+1 потому что, хотя Брайан Р. Бонди был хорош, вы подняли проблему прерывания / выхода (не вызывается деструктор объектов стека) и предложили альтернативу для процесса C ++ с интенсивным использованием RAII.
paercebal 02

Я искал способ выйти из программы без вызова dtor, и ваш ответ - именно то, что я искал! Спасибо
acemtp

Это, конечно, совершенно правильно, если действительно важно, что ваши автоматические деструкторы объектов не вызываются :-)
Крис Хуанг-Ливер

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

33

abort отправляет сигнал SIGABRT, exit просто закрывает приложение, выполняющее обычную очистку.

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

abort не будет выполнять уничтожение ваших статических и глобальных членов, но exit будет.

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

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

Смотрите следующий пример:

SomeClassType someobject;

void myProgramIsTerminating1(void)
{
  cout<<"exit function 1"<<endl;
}

void myProgramIsTerminating2(void)
{
  cout<<"exit function 2"<<endl;
}

int main(int argc, char**argv)
{
  atexit (myProgramIsTerminating1);
  atexit (myProgramIsTerminating2);
  //abort();
  return 0;
}

Комментарии:

  • Если abort раскомментирован: ничего не печатается и деструктор некоторого объекта не вызывается.

  • Если abort прокомментирован, как указано выше: будет вызван деструктор someobject, вы получите следующий результат:

функция выхода 2
функция выхода 1


Здесь он вызвал функцию выхода 2, ЗАТЕМ функцию выхода 1. gcc 4, Linux 2.6.
Strager

1
На странице руководства для atexit говорится: «Функции [зарегистрированные с помощью atexit] вызываются в обратном порядке; аргументы не передаются».
Strager

@strager прав, функции, зарегистрированные atexit, должны вызываться в обратном порядке, когда вызывается либо exit, либо основной возврат.
Роберт Гэмбл,

Запустив тест, выяснилось, что деструкторы глобальных экземпляров вызываются после всех обратных вызовов atexit.
Strager

+1 за напоминание людям, что ОС в конечном итоге освободит все выделенные ресурсы даже после вызова abort ().
Fingolfin

10

Когда программа вызывает exit(), происходят следующие вещи :

  • Функции, зарегистрированные atexitфункцией, выполняются
  • Все открытые потоки очищаются и закрываются, файлы, созданные с помощью tmpfile, удаляются
  • Программа завершается с указанным кодом выхода на хост

Функция abort() отправляет SIGABRTсигнал текущему процессу, если он не обнаружен, программа завершается без гарантии, что открытые потоки будут сброшены / закрыты или что временные файлы, созданные с помощью tmpfile, удалены, atexitзарегистрированные функции не вызываются, а не хосту возвращается нулевой статус выхода.


хмм. стандарт гласит, что программа не завершается только в том случае, если обработчик сигнала "не возвращает". у вас все хорошо с C.Можете ли вы представить любой сценарий, который позволил бы продолжить нормальное выполнение без возврата? Я представляю longjmp, но я не уверен, как он ведет себя в обработчиках сигналов.
Йоханнес Шауб - лит

В общем, вызов longjmp из обработчика сигнала не определен, но есть особый случай, когда сигнал был сгенерирован с помощью повышения / прерывания, поэтому я предполагаю, что это было бы теоретически возможно, хотя я не думаю, что когда-либо видел это. Теперь я собираюсь попробовать;)
Роберт Гэмбл

1
Кажется, это работает (разбито на несколько сообщений из-за ограничения в 300 символов): #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <setjmp.h> volatile sig_atomic_t do_abort = 1; jmp_buf env; void abort_handler (int i) {do_abort = 0; longjmp (env, 1);}
Роберт Гэмбл

int main (недействительно) {setjmp (env); put ("В setjmp"); если (do_abort) {сигнал (SIGABRT, abort_handler); put ("Прерывание вызова"); преждевременное прекращение (); } put ("Не прервано!"); вернуть 0; }
Роберт Гэмбл

В Ubuntu 7.04 это печатает: При setjmp Прерывание вызова При setjmp Не прервано!
Роберт Гэмбл,

5

На странице руководства exit ():

Функция exit () вызывает нормальное завершение процесса, и значение status & 0377 возвращается родителю.

На странице руководства abort ():

Abort () сначала разблокирует сигнал SIGABRT, а затем вызывает этот сигнал для вызывающего процесса. Это приводит к ненормальному завершению процесса, если только сигнал SIGABRT не перехвачен и обработчик сигнала не вернется.


4

abortпосылает SIGABRTсигнал. abortне возвращается к вызывающему. Обработчик SIGABRTсигнала по умолчанию закрывает приложение. stdioфайловые потоки сбрасываются, а затем закрываются. Однако деструкторов для экземпляров классов C ++ нет (не уверен в этом - возможно, результаты не определены?).

exitимеет свои собственные обратные вызовы, установленные с помощью atexit. Если обратные вызовы указаны (или только один), они вызываются в порядке, обратном порядку их регистрации (как стек), тогда программа завершается. Как и в случае abort, exitне возвращается к вызывающему. stdioфайловые потоки сбрасываются, а затем закрываются. Также вызываются деструкторы для экземпляров класса C ++.


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

@Gamble, конечно, я сам упомянул об этом несколько минут назад в комментарии к ответу @Bondy. Я отредактирую свой ответ, чтобы отразить это.
Strager
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.