Funktioniert exit(0) aus der stdlib IMMER?



  • Programmabbruch schrieb:

    So das sollte auch beweisen, dass new keine Exceptions wirft.

    Lies noch mal nach, wie man Dinge beweist. Ein Beispiel ist kein gültiges Beweismittel.

    Damit zeigst du bestenfalls, dass dein Compiler sich nicht an den Standard hält.



  • Programmabbruch schrieb:

    FALLS exit(0) identisch sein sollte mit einer return(0) Anweisung in der WinMain, müssten IMPLIZIT doch auch die Destruktoren der globalen Device-Objekte aufgerufen werden (Womit auch die dort codierten Device->Release() Anweisungen dafür sorgen könnten, dass die Tastatur für den Anwender nicht verloren ist!!!).

    Also stelle ich die Frage so:
    Bewirkt exit(0) EXAKT das gleiche wie eine return(0) Anweisung in der WinMain() oder nicht?

    Nein, tut es nicht - man: exit stammt noch aus C und kümmert sich deshalb nicht um die C++ Aufräumarbeiten (Destruktoraufrufe). Wenn du die main() per return verlässt, werden dagegen die Destruktoren aufgerufen, die noch erreichbar sind.

    (obwohl - natürlich könnte ein C++ Compiler im Startup-Code (d.h. vor der main()) auch eine Aufräumfunktion für alle globalen Objekte in die atexit()-Behandlung einklinken, aber das dürfte nicht im Standard vorgeschrieben sein)



  • "bewiesen" .... 😃

    Kurze Frage: Nutzt Du evtl. einen MS-Compiler (vielleicht VS6.0) ? Die sehen's bekanntermaßen nicht so eng mit dem Standard (zumindestens in der Defaulteinstellung) ... und erst recht nicht mit exception(specification)s.

    Es ist übrigens auch denkbar, dass der Compiler bei Dir das X ganz wegoptimiert - schließlich brauchst Du's ja nicht.

    Dewhurst, 'C++ Gotchas', #61 'Checking for Allocation Failure' schrieb:

    ...The standard behavior of new is to throw a bad_alloc exception in the event of allocation failure ... it is possible to employ the standard "nothrow" version of operator new that will return a null pointer on failure:

    int *ip = new (nothrow) int;
    

    ...

    Wenn Du also nicht nothrow angibst, sollte der Compiler

    Gruß,

    Simon2.



  • Simon2 schrieb:

    "bewiesen" .... 😃

    Kurze Frage: Nutzt Du evtl. einen MS-Compiler (vielleicht VS6.0) ? Die sehen's bekanntermaßen nicht so eng mit dem Standard (zumindestens in der Defaulteinstellung) ... und erst recht nicht mit exception(specification)s.

    Simon2.

    MS VC++.net Standard 2003. Offensichtlich ein Standard-Compiler. Weithin von tausenden oder gar Millionen Leuten verwendet. Und der nimmt es mit dem C++ Standard 'nicht so eng'? Sehr unwahrscheinlich...

    Es blieb mir nicht erspart, meine eigene exit() Variante zu schreiben. Die funktioniert jetzt wenigstens. Hatte nur gehofft, dass exit(0) aus der cstdlib eine Art Wunder-Funktion sein könnte, die mir die Arbeit erspart hätte.
    Danke für die Tipps bezüglich exit().

    Es ist gar nicht einmal so trivial, wie man glauben würde, ein größeres Programm auch wieder 'sauber' zu beenden, wenn schwere Fehler auftreten.

    mfg 🙂



  • Programmabbruch schrieb:

    MS VC++.net Standard 2003. Offensichtlich ein Standard-Compiler.

    Weil "Standard" Bestandteil des Namens ist, oder was? 🤡

    Weithin von tausenden oder gar Millionen Leuten verwendet.

    Was hat das mit der Standardkonformität zu tun? Genau, gar nichts.

    Und der nimmt es mit dem C++ Standard 'nicht so eng'? Sehr unwahrscheinlich...

    Ist aber so. Zumindest die 6er Version ist weit vom Standard entfernt. Und die Nachfolger haben, was new angeht, AFAIK dieses Verhalten als Default übernommen.



  • Komisch bei mir Verhält sich new in VS2003 entsprechend dem Standard (genauso wie 2005):

    try {
    	int *x = new int[800000000];
    	if(!x) cout << "omg" << endl;
    	delete []x;
    } catch(std::bad_alloc const &ex) {
    	cout << ex.what() << endl;
    }
    

    Erzeugt bei mir die Ausgabe: bad allocation
    Selbst wenn ich Enable C++ Exceptions auf false setze kommt eine Exception, da sich diese Option nur auf das Stack-Unwinding bezieht. Ich wüsste sonst auch keine Option wo man das sonst noch einstellen könnte (außer evtl. über eine Präprozessor-Direktive).

    Greetz


  • Mod

    Programmabbruch schrieb:

    #include<windows.h>
    #include<stdlib.h>
    
    int WINAPI WinMain(HINSTANCE hinst, HINSTANCE phinst,
    				   LPSTR commline,int showstyle){
       double* X = new double[200000000];
       if(!X){
    	   MessageBox(NULL,"Heap Overflow",NULL,0);
    	   exit(0);
       }
       return 0;
    				   }
    

    So das sollte auch beweisen, dass new keine Exceptions wirft. Man bekommt nämlich mit < 1.6 GB RAM in der Tat auch noch die MessageBox zu sehen. Zur Anzeige dieser MessageBox dürfte es allerdings erst gar nicht kommen, würde new wirklich eine Exception werfen, falls der Allokationsversuch fehlschlägt.

    Es bleibt also das Problem, dass man den Rückgabewert von new auf den NULL Zeiger hin überprüfen muss, und erst dann entscheiden kann, ob man das Programm mittels exit() beenden möchte oder eventuell an anderer Stelle Speicher freischaufeln kann, und einen neuen Anlauf versucht, mittels new Speicher zu beschaffen.
    FALLS exit(0) identisch sein sollte mit einer return(0) Anweisung in der WinMain, müssten IMPLIZIT doch auch die Destruktoren der globalen Device-Objekte aufgerufen werden (Womit auch die dort codierten Device->Release() Anweisungen dafür sorgen könnten, dass die Tastatur für den Anwender nicht verloren ist!!!).

    Also stelle ich die Frage so:
    Bewirkt exit(0) EXAKT das gleiche wie eine return(0) Anweisung in der WinMain() oder nicht?

    Besten Dank falls es jemand weiß!

    Das beweist nur, dass undefiniertes Verhalten, dass aus dem Nicht-Fangen von Exceptions resultiert, auch mal so aussehen kann, als ob keine Exception geworfen wurde. Das ist keine weltbewegende Erkenntnis. Zudem fehlt für ein standardkonformes Programm eine main Funktion. Ebenso ist es möglich, den globalen operator new mit einer leeren Exceptionspezifikation zu überladen, dann soll dieser im Fehlerfall NULL zurückgeben. Das ist dann aber gerade nicht das durch den Standard vorgegebene Verhalten und insofern hier uninteressant.

    Der Unterschied zwischen dem Aufruf von exit und einem return aus main besteht darin, dass exit die Destruktoren von automatischen Objekten nicht ausführt (was wohl bedeuten soll, dass statische Objekte aufgeräumt werden, zudem ist der Aufruf von exit aus dem Destruktor eines statischen Objektes heraus undefiniert). Was ein return aus einer Funktion mit dem Namen WinMain bewirkt, wirst du wohl deinen Compilerbauer fragen müssen.



  • camper schrieb:

    ...dass exit die Destruktoren von automatischen Objekten nicht ausführt (was wohl bedeuten soll, dass statische Objekte aufgeräumt werden, ...

    Fehlt da ein "nicht" oder bin ich gerade auf dem falschen Dampfer ?

    Gruß,

    Simon2.



  • Programmabbruch schrieb:

    Simon2 schrieb:

    "bewiesen" .... 😃

    Kurze Frage: Nutzt Du evtl. einen MS-Compiler (vielleicht VS6.0) ? Die sehen's bekanntermaßen nicht so eng mit dem Standard (zumindestens in der Defaulteinstellung) ... und erst recht nicht mit exception(specification)s.

    Simon2.

    MS VC++.net Standard 2003. Offensichtlich ein Standard-Compiler. Weithin von tausenden oder gar Millionen Leuten verwendet. Und der nimmt es mit dem C++ Standard 'nicht so eng'? Sehr unwahrscheinlich......

    Im Gegenteil.
    Vor "Standard" steht immer noch "MS" im Namen .... :p
    (soweit ich weiß, ist der MS-VS-6.0 der "standardunkonformste" Compiler, den es derzeit noch gibt).

    Vielleicht liegt aber auch ein kleines Mißverständnis vor: Unter "Standard" meinen wir hier kein "demokratisches Verfahren" ("Was die meisten machen, ist Standard"), sondern die Vorgabe durch das Standardisierungskommitee in der entsprechenden ISO-Spezifikation ...

    Gruß,

    Simon2.



  • Programmabbruch schrieb:

    Der Operator new wirft doch keine Exceptions! Im Misserfolgsfall bekommt man den NULL-Zeiger retour. Und dann muss man entsprechend reagieren (exit(0) oder exceptions werfen!). Also doch lieber mit Exceptions das Problem behandeln? Das Problem ist nur, dass zu dem Zeitpunkt, wo new fehlschlagen KÖNNTE, einige Hardware-Resourcen 'beschlagnahmt' sind und es deshalb nicht vorhersehbar ist, ob sie mittels Release() (codiert in den Device-Destruktoren) wieder freigegeben werden können.

    Vielleicht kennt jemand ein gutes Tutorial zu dem Thema:
    Eine (etwas größere) Anwendung im Problemfall 'möglichst sauber' terminieren?

    Danke für Tipps!

    Was verstehst du unter "möglichst sauber"?
    Die offizielle Version ist terminate() bzw. abort().
    Den Handler von terminate() kann man überschreiben, d.h. wenn du dich darauf verlassen können willst dass auch auf jeden Fall immer sofort das Programm beendet wird dann besser abort(), sonst besser terminate, da ein eventuell vorhandener anderer terminate() Handler u.U. noch was sinnvolles machen kann, wie z.B. nen core-dump zu schreiben oder etwas in der art.



  • Simon2 schrieb:

    Fehlt da ein "nicht" oder bin ich gerade auf dem falschen Dampfer ?

    Ich denke camper meint in der Tat, dass automatische Objekte nicht, statische Objekte aber sehr wohl abgeräumt werden (das wäre auch meine Einschätzung)


  • Mod

    LordJaxom schrieb:

    Simon2 schrieb:

    Fehlt da ein "nicht" oder bin ich gerade auf dem falschen Dampfer ?

    Ich denke camper meint in der Tat, dass automatische Objekte nicht, statische Objekte aber sehr wohl abgeräumt werden (das wäre auch meine Einschätzung)

    Das ergibt sich auch aus der Beschreibung des Verhaltens von return x in main: Das besteht darin, dass automatische Objekte zerstört werden und dann exit mit dem x als Argument ausgeführt wird. Wir wissen aber auch, dass jedenfalls beim normalen Beenden eines Programms statische Objekte zerstört werden - das kann dann aber nur durch exit geschehen.


Anmelden zum Antworten