iptal mi, sonlandırmak mı yoksa çıkmak mı?


112

Bu üçü arasındaki fark nedir ve düzgün bir şekilde idare edemediğim bir istisna durumunda programı nasıl sonlandırabilirim?


3
Bu bir kopya değil, bazı iyi cevaplara sahip bir alt kümedir. Stackoverflow.com/questions/397075/… ve C ++ olarak etiketlendi!
Ellie Kesselman

std::abortYıkıcıda bir istisna çözülemiyorsa mantıklıdır.
Daniel

1
Daha fazla bilgi için Andrzej'instd::terminate mükemmel C ++ blogundaki şu makalelere bakın: akrzemi1.wordpress.com/2011/09/28/who-calls-stdterminate , akrzemi1.wordpress.com/2011/10/05/using-stdterminate
Ohad Schneider

Yanıtlar:


3

Benim tavsiyem bunların hiçbirini kullanmamaktır. Bunun yerine, oradan ve basitçe catchbaşa çıkamayacağınız istisnalar . Bu, yığın çözme işleminin doğru şekilde gerçekleşeceği ve tüm yıkıcıların çağrıldığı garanti edildiği anlamına gelir. Diğer bir deyişle:main()return

int main() {
    try {
       // your stuff
    }
    catch( ... ) {
       return 1;    // or whatever
    }
}

8
@Neil: Temelde kabul edildi, ancak programın işleyemediği istisnalar raporlanmalı ve yeniden gözden geçirilmelidir. Uygulamanın çökmesine izin verin.
John Dibling

13
Yığının açıldığından emin olmak için her zaman esas olarak yakalamalısınız. Ama yakalamadan yeniden fırlatırdım. Bazı işletim sistemleri, hata ayıklamada derlediyseniz, hata ayıklama altyapısını otomatik olarak başlatma yeteneğine sahip olduğundan.
Martin York

5
Üst düzey bir işleyici tarafından bile yakalanmayan istisnalar, Windows Hata Bildirimi, Mac OS X hata raporları ve iPhone uygulama hata günlükleri gibi süreci atlayan ve geliştiricilerin dikkatini çekmek için istisna raporunu yükleyen bir sistem raporlama aracını çağırabilir.
JBRWilkinson

6
@John Benim için şaşırtıcı olmasının nedeni, istisnaların gerçekte nasıl uygulandığının ışığında mükemmel bir anlam ifade etse de, uygun bir işleyici bulunana kadar (veya sonlandırın) bir istisnanın "yığını yaydığı" soyutlamasını kırmasıdır. aranan). Ve sızdıran soyutlamalar, çoğu zaman kaçınılmaz olsa da, karşılaşıldığında mutlaka şaşırtıcıdır.
Tyler McHenry

11
-1 çünkü bu sorunun yarısını yanıtlamaz. "[İptal, sonlandırma veya çıkma arasındaki fark nedir?]" Bu daha iyi bir yanıttır: stackoverflow.com/a/397081/353094 Ayrıca stackoverflow.com/a/2820407/353094 harika bir yanıttır.
leetNightshade

149
  • abort , programın "anormal" sonunu gösterir ve POSIX sinyalini SIGABRT yükseltir; bu, bu sinyal için kaydettiğiniz herhangi bir işleyicinin çalıştırılacağı anlamına gelir, ancak program her iki durumda da son kelimeleri sonlandıracaktır. Genellikle abortbir C programında, hatanın hatalı girdi veya ağ arızası gibi bir şeyden ziyade programdaki bir hata olma olasılığı bulunan beklenmedik bir hata durumundan çıkmak için kullanırsınız . Örneğin, abortmantıksal olarak hiçbir zaman gerçekleşmemesi gereken bir veri yapısının içinde bir NULL işaretçisi olduğu tespit edilirse bu olabilir.

  • exit , programın "normal" bir sonunu belirtir, ancak bu yine de bir hata olduğunu gösterebilir (ancak bir hata değildir). Başka bir deyişle, exitkullanıcı ayrıştırılamayan girdi verdiyse veya bir dosya okunamadıysa bir hata koduyla karşılaşabilirsiniz. 0 çıkış kodu, başarıyı gösterir. exitayrıca isteğe bağlı olarak işleyicileri programı bitirmeden önce çağırır. Bunlar atexitve on_exitişlevlerine kaydedilir.

  • std :: terminate , işlenmemiş bir istisna olduğunda bir C ++ programında otomatik olarak çağrılan şeydir. Bu, abortistisnalar atarak tüm istisnai hatalarınızı rapor ettiğinizi varsayarsak , esasen C ++ ile eşdeğerdir . Bu std::set_terminate, varsayılan olarak basitçe çağıran işlev tarafından ayarlanan bir işleyiciyi çağırır abort.

C ++ 'da, genellikle arama yapmaktan abortveya exithatadan kaçınmak istersiniz , çünkü bir istisna atmak ve programın sonlandırılıp sonlandırılmayacağına kodun çağrı yığınının ilerlemesine izin vermesine izin vermek daha iyidir. exitBaşarı için kullanıp kullanmamanız bir durum meselesidir - programı içindeki return ifadesinden başka bir yerde sonlandırmanın mantıklı olup olmadığına bakılmaksızın main.

std::terminateC ++ 'da bile son bir hata raporlama aracı olarak düşünülmelidir. Sorun std::terminateyok işleyicisi sonlandırmak olduğunu değil işlenmeyen gitti istisna erişebilir, böylece ne olduğunu anlatmak için bir yolu yoktur. Genelde main'in tamamını bir try { } catch (std::exception& ex) { }blokta sarmalamanız çok daha iyidir . En azından o zaman istisnalardan türetilen istisnalar hakkında daha fazla bilgi bildirebilirsiniz std::exception(elbette kaynaklanmayan istisnalar std::exceptionyine de ele alınmayacaktır ).

Gövdesini tamamlayan mainiçinde try { } catch(...) { }çok daha iyi tekrar söz konusu istisna erişimi yok çünkü, işleyici sonlandırmak ayarı daha değil. Düzenleme: Neil Butterworth'un cevabına göre, bu durumda yığının çözülmesinin bir yararı var, bu (biraz şaşırtıcı bir şekilde) işlenmemiş bir istisna için doğru değil.


10
Bu yanıtı C ++ 11 bilgisi ile güncelleyebilir misiniz? Görünüşe göre artık catch'te (...) ve sonlandırma işleyicisinde istisnayı elde etmenin yolları var.
Klaim

1
C ++ sonlandırmak işleyici yapar yoluyla istisna erişebilir std::current_exception(). Buradaki örneğe bakın: akrzemi1.wordpress.com/2011/10/05/using-stdterminate
anorm

İnceleyemeyeceğiniz için mevcut istisnayı alabilmeniz önemli değil. Tek yapabileceğin onu yeniden atmak.
seattlecpp

2
@seattlecpp onu yeniden atabilir ve daha sonra inceleyebileceğiniz bir referans yakalayabilirsiniz
gpeche

16

std :: abort ve std :: exit (ve daha fazlası: std :: _ Exit, std :: quick_exit) sadece daha düşük seviyeli fonksiyonlardır. Bunları programa tam olarak ne yapmasını istediğinizi söylemek için kullanırsınız: hangi yıkıcıları (ve eğer) çağırmalı, başka hangi temizleme işlevlerini çağırmalı, hangi değeri döndürmeli vb.

std :: terminate daha yüksek seviyeli bir soyutlamadır: programda bir hata oluştuğunu ve herhangi bir nedenle bir istisna atarak işlemenin mümkün olmadığını belirtmek için (çalışma zamanı veya siz tarafından) çağrılır. Bunun gerekliliği, genellikle istisna mekanizmasının kendisinde hata oluştuğunda ortaya çıkar, ancak programınızın verilen hatanın ötesinde devam etmesini istemediğinizde bunu istediğiniz zaman kullanabilirsiniz. Std :: denir sonlandırmak zaman durumların tam listesini derlenmiş benim sonrası. Std :: terminate'in ne yapacağı belirtilmemiştir, çünkü onun kontrolü sizdedir. Herhangi bir işlevi kaydederek davranışı yapılandırabilirsiniz. Sahip olduğunuz sınırlamalar, işlevin hata sitesine geri dönememesi ve bir istisna yoluyla çıkamamasıdır, ancak teknik olarak mesaj pompanızı içeriden başlatabilirsiniz. İçeride yapabileceğiniz yararlı şeylerin listesi için diğer yazıma bakın .

Özellikle, std :: terminate'in, ele alınamayan atılan bir istisna nedeniyle std :: terminate çağrıldığı bağlamlarda bir istisna işleyicisi olarak kabul edildiğini ve istisnanın ne olduğunu kontrol edip C ++ kullanarak inceleyebileceğinizi unutmayın. 11 std :: rethrow_exception ve std :: current_exception kullanarak. Hepsi benim yazımda .


Programın sistem sinyalleri nedeniyle sonlanması durumunda bir temizleme işleyicisinin olması tavsiye edilir mi? Örneğin, geçersiz bellek erişimi SIGSEGV sinyalinin oluşmasına neden olur. Bu durumda, programın sonlandırılmasına ve çekirdek dosyaya sahip olmasına izin vermek veya temizleme işlemini yapmak için bir sinyal işleyici kaydettirmek iyi midir? Std :: terminate ile çalışırken temizleme yapmaya kıyasla sistem sinyallerini işlerken temizleme yapma endişesi var mı?
kartik trivikram

12

quick_exit () !

Programınız çok iş parçacıklıysa, çağrı exit()büyük olasılıkla bir çökmeye neden olacaktır çünkü global / statik std::threadnesneler iş parçacıklarından çıkmadan yok edilmeye çalışılacaktır.

Bir hata kodu döndürmek ve programdan normal şekilde (aşağı yukarı) çıkmak istiyorsanız quick_exit(), çok iş parçacıklı programları çağırın . Anormal sonlandırma için (hata kodunu belirleme olanağınız olmadan) abort()veya std::terminate()çağrılabilir.

Not: quick_exit (), 2015 sürümüne kadar MSVC ++ tarafından desteklenmiyordu .


4
  • terminate, çağrıldığında ne olacağını kaydetme olanağını size bırakır. Diğer ikisinden biri olmalı.
  • çıkış, bir çıkış durumunu belirlemeye izin veren normal bir çıkıştır. At_exit () tarafından kaydedilen işleyiciler çalıştırılır
  • iptal anormal bir çıkıştır. Çalıştırılan tek şey SIGABRT için sinyal işleyicidir.

4
  • terminate (), işlenemeyen bir istisna meydana geldiğinde otomatik olarak çağrılır. Varsayılan olarak, abort () çağrılarını sonlandırın (). Set_terminate () işlevi ile özel bir tutamaç ayarlayabilirsiniz.

    abort () SIGABRT sinyalini gönderir.

    exit () mutlaka kötü bir şey değildir. Uygulamadan başarıyla çıkar ve atexit () işlevlerini LIFO sırasında çağırır. Bunu normalde C ++ uygulamalarında görmüyorum, ancak sonunda bir çıkış kodu gönderdiği birçok unix tabanlı uygulamada görüyorum. Genellikle bir çıkış (0), uygulamanın başarılı bir şekilde çalıştırıldığını gösterir.


8
Başarısız! Hem Unix'te hem de DOS'ta, exit (0) başarıyı gösterir ve exit () 'ye iletilen diğer herhangi bir değer başarısızlığı gösterir, tam tersi değil!
Richard Barrell
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.