Ich möchte, dass mein C ++ - Code nicht mehr ausgeführt wird, wenn eine bestimmte Bedingung erfüllt ist, bin mir aber nicht sicher, wie ich das tun soll. Wenn also eine if
Aussage wahr ist, beenden Sie den Code wie folgt:
if (x==1)
{
kill code;
}
main()
Verwendung return, bei Funktionen wird ein korrekter Rückgabewert verwendet oder eine ordnungsgemäße Ausnahme ausgelöst. Nicht benutzenexit()
!NDEBUG
defined kompiliert wird ,assert
wird es wahrscheinlich zu einem No-Op. Sie sollten sich also nicht mehr darauf verlassen, als Fehler zu erkennen.return
vonmain()
ist vollkommen logisch. Hiermit wird der vom Programm an das Betriebssystem gemeldete Exit-Code festgelegt, was in vielen Fällen hilfreich sein kann (wenn Ihr Programm beispielsweise als Teil eines größeren Prozesses verwendet werden kann).exit()
als schlecht angesehen? - SO 25141737 und Wie beende ich ein C ++ - Programm? - SO 1116493 sind jetzt als Duplikate dieses geschlossen. Die erste enthält einen Verweis auf "Nur-Crash-Software", der einen Blick wert sein könnte, wenn auch nur, um Sie zum Nachdenken über das Schreiben robuster Software anzuregen.Antworten:
Es gibt verschiedene Möglichkeiten, aber zuerst müssen Sie verstehen, warum die Objektbereinigung wichtig ist, und daher ist der Grund
std::exit
unter C ++ - Programmierern marginalisiert.RAII und Stack Unwinding
C ++ verwendet eine Redewendung namens RAII , was in einfachen Worten bedeutet, dass Objekte eine Initialisierung im Konstruktor und eine Bereinigung im Destruktor durchführen sollten. Zum Beispiel die
std::ofstream
Klasse die Datei während des Konstruktors öffnen, dann führt der Benutzer Ausgabeoperationen für sie aus, und schließlich wird am Ende ihres Lebenszyklus, der normalerweise durch seinen Umfang bestimmt wird, der Destruktor aufgerufen, der die Datei im Wesentlichen schließt und leert Alle auf die Festplatte geschriebenen Inhalte.Was passiert, wenn Sie nicht zum Destruktor gelangen, um die Datei zu leeren und zu schließen? Wer weiß! Möglicherweise werden jedoch nicht alle Daten in die Datei geschrieben.
Betrachten Sie zum Beispiel diesen Code
Was bei jeder Möglichkeit passiert, ist:
os
informiert ist, indem es seinen Destruktor aufruft und eine ordnungsgemäße Bereinigung durch Schließen und Leeren der Datei auf die Festplatte durchführt.inner_mad
, durchläuft der Abwickler den Stapel vonmad
und führtmain
eine ordnungsgemäße Bereinigung durch. Alle Objekte werden ordnungsgemäß zerstört, einschließlichptr
undos
.exit
ist eine C-Funktion und weder bekannt noch kompatibel mit den C ++ - Redewendungen. Es werden keine Bereinigungen für Ihre Objekte durchgeführt, auch nichtos
im selben Bereich. Ihre Datei wird also nicht richtig geschlossen und aus diesem Grund wird der Inhalt möglicherweise nie in sie geschrieben!return 0
und somit den gleichen Effekt wie Möglichkeit 1 hat, dh eine ordnungsgemäße Bereinigung.Aber sei dir nicht so sicher, was ich dir gerade gesagt habe (hauptsächlich Möglichkeiten 2 und 3); Lesen Sie weiter und wir werden herausfinden, wie Sie eine ordnungsgemäße ausnahmebasierte Bereinigung durchführen.
Mögliche Möglichkeiten zum Beenden
Rückkehr von der Hauptstraße!
Sie sollten dies nach Möglichkeit tun. Ziehen Sie es immer vor, von Ihrem Programm zurückzukehren, indem Sie einen ordnungsgemäßen Exit-Status von main zurückgeben.
Der Aufrufer Ihres Programms und möglicherweise das Betriebssystem möchten möglicherweise wissen, ob das, was Ihr Programm tun sollte, erfolgreich ausgeführt wurde oder nicht. Aus dem gleichen Grund sollten Sie entweder Null zurückgeben oder
EXIT_SUCCESS
signalisieren, dass das Programm erfolgreich beendet wurde, undEXIT_FAILURE
um zu signalisieren, dass das Programm nicht erfolgreich beendet wurde , ist jede andere Form von Rückgabewert implementierungsdefiniert ( §18.5 / 8 ).Sie befinden sich jedoch möglicherweise sehr tief im Aufrufstapel, und es kann schmerzhaft sein, alles zurückzugeben ...
[Nicht] eine Ausnahme auslösen
Durch das Auslösen einer Ausnahme wird eine ordnungsgemäße Objektbereinigung mithilfe des Abwickelns des Stapels durchgeführt, indem der Destruktor jedes Objekts in einem früheren Bereich aufgerufen wird.
Aber hier ist der Haken ! Es ist implementierungsdefiniert, ob das Abwickeln des Stapels durchgeführt wird, wenn eine ausgelöste Ausnahme nicht behandelt wird (durch die catch (...) -Klausel) oder selbst wenn Sie eine
noexcept
Funktion in der Mitte des Aufrufstapels haben. Dies ist in §15.5.1 [außer.terminate] angegeben :Also müssen wir es fangen!
Wirf eine Ausnahme und fange sie an der Hauptleitung!
Da nicht erfasste Ausnahmen möglicherweise kein Abwickeln des Stapels durchführen (und folglich keine ordnungsgemäße Bereinigung durchführen) , sollten wir die Ausnahme in main abfangen und dann einen Exit-Status zurückgeben (
EXIT_SUCCESS
oderEXIT_FAILURE
) zurückgeben.Ein möglicherweise gutes Setup wäre also:
[Nicht] std :: exit
Dies führt keine Abwicklung des Stapels durch, und kein lebendes Objekt auf dem Stapel ruft seinen jeweiligen Destruktor auf, um eine Bereinigung durchzuführen.
Dies wird in §3.6.1 / 4 [basic.start.init] durchgesetzt :
Denken Sie jetzt darüber nach, warum sollten Sie so etwas tun? Wie viele Gegenstände haben Sie schmerzhaft beschädigt?
Andere [als schlechte] Alternativen
Es gibt andere Möglichkeiten, ein Programm zu beenden (außer Abstürzen) , aber sie werden nicht empfohlen. Nur zur Verdeutlichung werden sie hier vorgestellt. Beachten Sie, wie normale Programmbeendigung nicht mittleres Stack Abwickeln , sondern eine Ordnung Zustand für das Betriebssystem.
std::_Exit
verursacht eine normale Programmbeendigung, und das war's.std::quick_exit
bewirkt eine normale Programmbeendigung und ruftstd::at_quick_exit
Handler auf, es wird keine weitere Bereinigung durchgeführt.std::exit
verursacht eine normale Programmbeendigung und ruft dannstd::atexit
Handler auf. Andere Arten von Bereinigungen werden durchgeführt, z. B. das Aufrufen von Destruktoren für statische Objekte.std::abort
verursacht eine abnormale Programmbeendigung, es wird keine Bereinigung durchgeführt. Dies sollte aufgerufen werden, wenn das Programm auf eine wirklich, wirklich unerwartete Weise beendet wurde. Es wird nichts anderes tun, als dem Betriebssystem die abnormale Beendigung zu signalisieren. Einige Systeme führen in diesem Fall einen Core-Dump durch.std::terminate
ruft das auf,std::terminate_handler
wasstd::abort
standardmäßig aufruft .quelle
new
Würfestd::bad_alloc
und Ihr Programm haben vergessen, diese Ausnahme irgendwo abzufangen), den Stapel vor dem Beenden nicht ordnungsgemäß abwickelt. Dies scheint dumm zu mir: Es wäre leicht gewesen , um im wesentlichen den Anruf wickeltmain
in einem trivialentry{
-}catch(...){}
Block, der das Abwickeln Stapel gewährleisten würde , ist in solchen Fällen richtig gemacht, ohne Kosten ( und damit meine ich: Programme nicht dies mit zahlt nicht Elfmeter). Gibt es einen bestimmten Grund, warum dies nicht getan wird?std::abort
stattdessen verwendet, damit das Betriebssystem alle Speicher, Sockets und Dateideskriptoren freigeben kann, ohne sie für eine Minute auszutauschen.Wie Martin York erwähnte, führt der Ausgang keine notwendige Bereinigung durch, wie dies bei der Rückgabe der Fall ist.
Es ist immer besser, die Rückgabe anstelle des Ausgangs zu verwenden. Wenn Sie sich nicht in main befinden, wo immer Sie das Programm beenden möchten, kehren Sie zuerst zu main zurück.
Betrachten Sie das folgende Beispiel. Mit dem folgenden Programm wird eine Datei mit dem genannten Inhalt erstellt. Wenn die Rückgabe jedoch kommentiert und nicht kommentiert ist (0), versichert Ihnen der Compiler nicht, dass die Datei den erforderlichen Text enthält.
Nicht nur das, mehrere Exit-Punkte in einem Programm erschweren das Debuggen. Verwenden Sie exit nur, wenn dies gerechtfertigt werden kann.
quelle
return (EXIT_SUCCESS);
stattdessen für modernes C ++return(0)
Rufen Sie die
std::exit
Funktion auf.quelle
exit()
wenn Ihr Bibliothekscode in meinem Host-Prozess ausgeführt wird - letzterer wird mitten im Nirgendwo beendet.Die Leute sagen "Call Exit (Rückkehrcode)", aber das ist eine schlechte Form. In kleinen Programmen ist es in Ordnung, aber es gibt eine Reihe von Problemen damit:
Wirklich, das einzige Mal, wenn Sie das Problem beenden sollten, ist mit dieser Zeile in main.cpp:
Wenn Sie exit () verwenden, um Fehler zu behandeln, sollten Sie sich mit Ausnahmen (und Verschachtelungsausnahmen) als einer viel eleganteren und sichereren Methode vertraut machen.
quelle
return 0;
Setzen Sie das, wo immer Sie wollen,int main()
und das Programm wird sofort geschlossen.quelle
main
.int main()
jedoch anders. Das Programmint main()
beginnt und endet. Es gibt keinen anderen Weg, dies zu tun. Das Programm wird ausgeführt, bis Sie true oder false zurückgeben. Fast die ganze Zeit geben Sie 1 oder true zurück, um anzuzeigen, dass das Programm korrekt geschlossen wurde (z. B. false, wenn Sie keinen Speicher freigeben konnten oder aus welchem Grund auch immer). Es ist immer eine schlechte Idee, das Programm selbst ausführen zu lassen. Beispiel:int main() { int x = 2; int foo = x*5; std::cout << "blah"; }
int main
. Es ist jedoch nicht immer eine gute Idee, mehrere return-Anweisungen in einer Hauptroutine zu haben. Eine mögliche Einschränkung besteht darin, die Lesbarkeit des Codes zu verbessern. Verwenden Sie jedoch so etwas wie ein boolesches Flag, das den Status ändert, um zu verhindern, dass bestimmte Codeabschnitte des Codes in diesem Anwendungsstatus ausgeführt werden. Persönlich finde ich, dass eine gemeinsame return-Anweisung die meisten Anwendungen besser lesbar macht. Zuletzt Fragen zur Speicherbereinigung und zum ordnungsgemäßen Schließen von E / A-Objekten vor dem Beenden.true
vonmain
einer korrekten Beendigung anzuzeigen. Sie müssen Null oderEXIT_SUCCESS
(oder, wenn Sie möchten,false
die implizit in Null konvertiert werden) zurückgeben, um eine normale Beendigung anzuzeigen. Um einen Fehler anzuzeigen, können Sie zurückkehrenEXIT_FAILURE
. Jede andere Codebedeutung ist implementierungsdefiniert (auf POSIX-Systemen würde dies den tatsächlichen Fehlercode bedeuten).Das Programm wird beendet, wenn der Ausführungsablauf das Ende der Hauptfunktion erreicht.
Um es vorher zu beenden, können Sie die Funktion exit (int status) verwenden, wobei status ein Wert ist, der an den Start des Programms zurückgegeben wird. 0 zeigt normalerweise einen fehlerfreien Zustand an
quelle
Geben Sie entweder einen Wert von Ihrem zurück
main
oder verwenden Sie dieexit
Funktion. Beide nehmen eine int. Es spielt keine Rolle, welchen Wert Sie zurückgeben, es sei denn, Sie haben einen externen Prozess, der nach dem Rückgabewert sucht.quelle
Wenn Sie irgendwo tief im Code einen Fehler haben, lösen Sie entweder eine Ausnahme aus oder legen Sie den Fehlercode fest. Es ist immer besser, eine Ausnahme auszulösen, als Fehlercodes festzulegen.
quelle
Im Allgemeinen würden Sie die
exit()
Methode mit einem geeigneten Exit-Status verwenden .Null würde einen erfolgreichen Lauf bedeuten. Ein Status ungleich Null zeigt an, dass ein Problem aufgetreten ist. Dieser Exit-Code wird von übergeordneten Prozessen (z. B. Shell-Skripten) verwendet, um festzustellen, ob ein Prozess erfolgreich ausgeführt wurde.
quelle
return 0;
. Ich gehe davon aus, dassexit()
esassert(false);
so ist und daher nur in der Entwicklung verwendet werden sollte, um Probleme frühzeitig zu erkennen.Über den Aufruf von exit (error_code) hinaus, der atexit-Handler, aber keine RAII-Destruktoren usw. aufruft, verwende ich immer mehr Ausnahmen.
Mein Hauptprogramm sieht immer mehr so aus
Dabei wird sekundäres_Main dort abgelegt, wo das gesamte ursprünglich platzierte Material abgelegt wird - dh das ursprüngliche Haupt wird in sekundäres_Main umbenannt und das obige Stub-Haupt wird hinzugefügt. Dies ist nur eine Kleinigkeit, damit nicht zu viel Code zwischen dem Fach und dem Hauptfang vorhanden ist.
Wenn Sie möchten, fangen Sie andere Ausnahmetypen ab.
Ich mag es, String-Fehlertypen wie std :: string oder char * abzufangen und diese im catch-Handler in main zu drucken.
Mit solchen Ausnahmen können zumindest RAII-Destruktoren aufgerufen werden, damit sie bereinigen können. Welches kann angenehm und nützlich sein.
Insgesamt spielen C-Fehlerbehandlung - Exit und Signale - und C ++ - Fehlerbehandlung - Try / Catch / Throw-Ausnahmen - bestenfalls inkonsistent zusammen.
Dann, wo Sie einen Fehler erkennen
oder ein spezifischerer Ausnahmetyp.
quelle
exit
Ihr Programm aufzurufen . Da du drin bistmain
, kannst du einfachreturn exitCode;
.Wenn sich Ihre if-Anweisung in Loop befindet, können Sie verwenden
Wenn Sie einem Code entkommen und die Schleife fortsetzen möchten, verwenden Sie:
fortsetzen;
Wenn Ihre if-Anweisung nicht in Loop ist, können Sie Folgendes verwenden:
quelle
Dude ...
exit()
Funktion ist unter stdlib.h definiertSie müssen also einen Präprozessor hinzufügen.
Fügen Sie
include stdlib.h
den Header-Bereich einVerwenden
exit();
Sie dann, wo immer Sie möchten, aber denken Sie daran, eine Interger-Nummer in die Klammer von exit zu setzen.beispielsweise:
quelle
Wenn der Zustand, auf den ich teste, wirklich schlechte Nachrichten sind, mache ich Folgendes:
Dies gibt mir einen schönen Kern, von dem aus ich die Situation untersuchen kann.
quelle
Um eine Bedingung zu brechen, verwenden Sie die Rückgabe (0).
In Ihrem Fall wäre es also:
quelle