Яка різниця між виходом () і перервати ()?


Відповіді:


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 тому, що, хоча Брайан Р. Бонді був хорошим, ви все-таки підняли проблему переривання або виходу (не деструктор зв'язаних об'єктів стека) і запропонували альтернативу для RAII-інтенсивного C ++ процесу.
paercebal

Я шукав спосіб виходу з програми без виклику dtor, і ваша відповідь - це саме те, що я шукав! Дякую
acemtp

Це абсолютно правильно, звичайно, якщо насправді має значення те, що ваші автоматичні деструктори не викликаються :-)
Кріс Хуан-Лівер

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

33

аборт надсилає сигнал SIGABRT, вихід просто закриває програму, виконуючи звичайну очистку.

Ви можете обробляти сигнал переривання, як хочете, але поведінка за замовчуванням - це закрити програму, а також кодом помилки.

аборт не буде виконувати знищення об'єктів ваших статичних і глобальних членів, але вихід буде.

Звичайно, якщо програма повністю закрита, операційна система звільнить незапалену пам'ять та інші ресурси.

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

Дивіться наступний приклад:

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;
}

Коментарі:

  • Якщо аборт не коментується: нічого не друкується і деструктор якогось об'єкта не буде викликаний.

  • Якщо аборт буде прокоментовано як вище: буде викликано якийсь деструктор об'єкта, ви отримаєте такий вихід:

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


Тут вона називається функцією виходу 2, а потім функція виходу 1. gcc 4, Linux 2.6.
страгер

1
Сторінка Man для atexit говорить: "Функції [зареєстровані за допомогою atexit] викликаються у зворотному порядку; аргументи не передаються."
страгер

@strager має рацію, функції, зареєстровані atexit, повинні викликатися в зворотному порядку, коли викликається або вихід, або основна віддача.
Роберт Гембл

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

+1 для нагадування людям про те, що ОС врешті-решт звільнить усі виділені ресурси навіть після виклику аборту ().
Фінгольфін

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> летючий sig_atomic_t do_abort = 1; jmp_buf env; void abort_handler (int i) {do_abort = 0; longjmp (env, 1);}
Роберт Гембл

int main (void) {setjmp (env); put ("At setjmp"); if (do_abort) {сигнал (SIGABRT, abort_handler); ставить ("Виклик перервати"); аборт (); } put ("Не перервав!"); повернути 0; }
Роберт Гембл

На Ubuntu 7.04 ця версія друкується: На setjmp Calling abort At setjmp Not abort!
Роберт Гембл

5

З сторінки керівництва exit ():

Функція exit () викликає нормальне завершення процесу, і значення статусу & 0377 повертається батьківському.

З сторінки посібника про переривання ()

Аборт () спочатку розблокує сигнал SIGABRT, а потім піднімає цей сигнал для процесу виклику. Це призводить до ненормального припинення процесу, якщо сигнал SIGABRT не зачеплений і обробник сигналу не повернеться.


4

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

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


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

@ Gamble, Звичайно, я згадував про це кілька хвилин тому в коментарі до відповіді @ Bondy. Я відредагую власну відповідь, щоб це відобразити.
страгер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.