Exit () ve abort () arasındaki fark nedir?


Yanıtlar:


116

abort()atexit()ilk olarak kaydedilen işlevleri çağırmadan ve önce nesnelerin yıkıcılarını çağırmadan programınızdan çıkar . exit()programınızdan çıkmadan önce her ikisini de yapar. Yine de otomatik nesneler için yıkıcılar çağırmaz. Yani

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

Yok edecek ave bdüzgün, fakat yıkıcı aramayacak c. abort()hiçbir nesnenin yıkıcılarını çağırmazdı. Bu talihsiz bir durum olduğu için, C ++ Standardı, uygun şekilde sonlandırmayı sağlayan alternatif bir mekanizma tanımlar:

Otomatik depolama süresi olan nesnelerin tümü, işlevi main()hiçbir otomatik nesne içermeyen ve çağrıyı yürüten bir programda yok edilir exit(). Kontrol main(), yakalanan bir istisna atılarak doğrudan böyle bir a aktarılabilir 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);
    }
}

Aramak yerine exit()bu kodu düzenleyin throw exit_exception(exit_code);.


2
+1 çünkü Brian R. Bondy iyiyken, iptal / çıkış problemini ortaya çıkardınız (yığın nesnelerinin yok edicisi değil) ve RAII-yoğun C ++ süreci için bir alternatif sundunuz.
paercebal

Dtor'u aramadan bir programdan çıkmanın bir yolunu arıyordum ve cevabınız tam da aradığım şeydi! Teşekkürler
acemtp

Bu elbette tamamen doğru, eğer otomatik nesne yıkıcılarınızın çağrılmaması gerçekten
önemliyse

Bildiğim kadarıyla, çıkış ve iptal arasındaki diğer bir fark, iptalin (işletim sistemi yapılandırmasına bağlı olarak) bir çekirdek dökümü oluşturmaya yol açması olabilir.
Dirk Herrmann

33

abort bir SIGABRT sinyali gönderir, çıkış sadece normal temizleme gerçekleştiren uygulamayı kapatır.

Bir iptal sinyalini istediğiniz gibi işleyebilirsiniz , ancak varsayılan davranış, uygulamayı bir hata koduyla da kapatmaktır.

abort , statik ve global üyeleriniz için nesne yok etme gerçekleştirmez, ancak çıkış işlemi gerçekleştirir.

Tabii ki, uygulama tamamen kapatıldığında, işletim sistemi, işlenmemiş bellek ve diğer kaynakları serbest bırakacaktır.

İkisinde de iptal ve çıkış programı sonlandırma, dönüş kodu başvurunuzu başladı ana süreç iade edilecektir (varsayılan davranışı geçersiz vermedi varsayarak).

Aşağıdaki örneğe bakın:

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

Yorumlar:

  • Eğer iptal uncommented: hiçbir şey yazdırılır ve SomeObject yıkıcı denilen edilmeyecektir.

  • Eğer iptal yukarıdaki gibi yorumlanır: adı verilecek SomeObject yıkıcının şu çıktıları elde edecek:

çıkış işlevi 2
çıkış işlevi 1


Burada çıkış işlevi 2 SONRA çıkış işlevi 1 olarak adlandırılır. Gcc 4, Linux 2.6.
strager

1
Atexit için man sayfası şöyle diyor: "[atexit kullanılarak kaydedilen] işlevler ters sırada çağrılır; hiçbir bağımsız değişken aktarılmaz."
strager

@strager haklı, atexit tarafından kaydedilen işlevlerin ya çıkış çağrıldığında ya da ana dönüşlerde ters sırada çağrılması gerekiyor.
Robert Gamble

Bir test yapıldı ve tüm atexit geri çağırmalarından sonra küresel örnekler için yıkıcıların çağrıldığı görülüyor.
strager

İnsanlara, bir abort () çağrısından sonra bile işletim sisteminin tahsis edilen tüm kaynakları sonunda serbest bırakacağını hatırlatan +1.
Fingolfin

10

Bir program exit() çağırdığında aşağıdaki şeyler olur :

  • İşlev tarafından kaydedilen atexitişlevler yürütülür
  • Tüm açık akışlar temizlenir ve kapatılır, tarafından oluşturulan dosyalar tmpfilekaldırılır
  • Program, ana bilgisayara belirtilen çıkış koduyla sona erer

abort() Fonksiyonu gönderir SIGABRTo programı açık akışları / kızardı kapalı olduğu veya üzerinden oluşturulan geçici dosyalar hiçbir garantisi ile sonlandırılır yakalandı değilse, mevcut sürecin sinyal tmpfilekaldırılır, atexitkayıtlı fonksiyonlar denir değildir ve bir sivil ana bilgisayara sıfır çıkış durumu döndürülür.


hı. standart, programın yalnızca sinyal işleyici "dönmezse" sonlandırılmayacağını söyler. C. ile oldukça iyisiniz, geri dönmeden normal yürütmeye devam etmesine izin verecek herhangi bir senaryo hayal edebiliyor musunuz? longjmp'yi hayal ediyorum, ancak sinyal tutucularda nasıl davrandığından emin değilim.
Johannes Schaub - litb

Genel olarak, bir sinyal işleyiciden longjmp çağırmak tanımsızdır, ancak sinyalin yükseltme / durdurma ile üretildiği zaman için özel bir durum vardır, bu yüzden sanırım bunun teorik olarak mümkün olacağını sanmıyorum, ancak daha önce yapıldığını görmedim. Şimdi denemek zorundayım;)
Robert Gamble

1
Bu işe yarıyor gibi görünüyor (300 karakter sınırından dolayı birden fazla gönderiye bölünmüş): #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);}
Robert Gamble

int main (void) {setjmp (env); koyar ("setjmp'de"); eğer (do_abort) {sinyal (SIGABRT, abort_handler); koyar ("İptal çağrısı"); durdurma (); } koyar ("İptal etmedi!"); dönüş 0; }
Robert Gamble

Ubuntu 7.04'te bu şunu yazdırır: setjmp'de Çağrı durdurma setjmp'de İptal etmedi!
Robert Gamble

5

Exit () kılavuz sayfasından:

Exit () işlevi, normal işlemin sonlandırılmasına neden olur ve & 0377 durumunun değeri üst öğeye döndürülür.

Abort () kılavuz sayfasından:

Abort () ilk olarak SIGABRT sinyalinin engelini kaldırır ve ardından çağıran işlem için bu sinyali yükseltir. Bu, SIGABRT sinyali yakalanmadıkça ve sinyal işleyici geri dönmedikçe işlemin anormal sonlandırılmasına neden olur.


4

abortSIGABRTsinyali gönderir . abortarayana geri dönmez. SIGABRTSinyal için varsayılan işleyici uygulamayı kapatır. stdiodosya akışları temizlenir, ardından kapatılır. Bununla birlikte, C ++ sınıfı örnekleri için yıkıcılar değildir (bundan emin değil - belki de sonuçlar tanımsızdır?).

exitile ayarlanmış kendi geri aramaları vardır atexit. Geri aramalar belirtilirse (veya yalnızca biri), kayıt sıralarının tersi sırayla çağrılırlar (bir yığın gibi), ardından program çıkar. Olduğu gibi abort, exitarayana döndürmez. stdiodosya akışları temizlenir, ardından kapatılır. Ayrıca, C ++ sınıf örnekleri için yıkıcılar çağrılır.


exit, atexit aracılığıyla kaydedilmiş birden çok geri arama işlevine sahip olabilir, exit çağrıldığında tüm geri arama işlevleri, kaydedildikleri sıranın tersi sırayla çağrılacaktır.
Robert Gamble

@Gamble, Elbette, birkaç dakika önce @ Bondy'nin cevabına bir yorumda kendimden bahsetmiştim. Bunu yansıtmak için kendi cevabımı düzenleyeceğim.
strager
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.