Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

25.11.2013, 18:11

No memory im Konstruktor abfangen

Hallo,

gibts für den Fall einen möglichst sauberen Weg? Denkbar wäre z.B. eine Image-Klasse, die über einen Konstruktor mit size_u x size_v aufgerufen wird und dann per new ein char-array anlegt. Wie handhabt ihr das jetzt, falls z.B. im Konstruktor nicht mehr genug Speicher da ist? Kann man das einfach ignorieren oder kann man den User zumindest irgendwie noch mit mehr Output versorgen?
Ich hab gelesen, dass man solche Fälle am besten mit Exceptions behandelt, aber bad_alloc wird da doch automatisch geworfen oder nicht?

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

25.11.2013, 19:12

Out of memory ist ohnehin Feierabend. Wenn's kommt, kommt's. Man sollte eher darauf achten, dass das erst gar nicht passieren kann. 3GB Speicher, da muss man schon reichlich schludern ;)
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Helmut

5x Contest-Sieger

Beiträge: 692

Wohnort: Bielefeld

  • Private Nachricht senden

3

25.11.2013, 19:55

Fehlerbehandlung ist halt immer individuell. Ich hab mal einen Clipboard Manager geschrieben. Wenn dieser keinen Speicher für das kopierte Bild anfordern konnte (was durchaus passiert) zeigt er halt an, dass der Arbeitsspeicher nicht ausreicht, um das Bild anzuzeigen.
Ich machs normalerweise so, dass wenn ich größere Mengen an Arbeitsspeicher allokiere oder die Menge durch den Benutzer beeinflusst werden kann (zB beim Datei einlesen) ne ordentliche Fehlerbehandlung mache und die auch teste, ansonsten benutze ich einfach new und das Programm crasht halt dann mit der Exception. Windows zeigt auch ne Meldung an, wenn der Arbeitsspeicher knapp wird, sodass der Benutzer sich dann nicht groß wundern dürfte, wenn Programme abstürzen.
Sei stets geduldig gegenüber Leuten, die nicht mit dir übereinstimmen. Sie haben ein Recht auf ihren Standpunkt - trotz ihrer lächerlichen Meinung. (F. Hollaender)

4

26.11.2013, 06:49

Im Falle einer std::bad_alloc ist der Drops ja meist gelutscht und man kann das Programm getrost hart abstürzen lassen (aka Ausnahme nicht behandeln).

Wenn das Programm jedoch weiter laufen kann, sollte m. E. std::bad_alloc vom aufrufenden Kontext abgefangen werden. Hier sollte man beachten, dass das Objekt im Falle einer Ausnahme nicht existiert und der Destruktor nicht aufgerufen wird. Alle angeforderten Ressourcen müssen daher im Konstruktor freigegeben werden.

Die Klasse sollte möglichst so gestaltet sein, dass der Destruktor nichts mehr zu tun hat -> Smartpointer und ähnliche Mechanismen.

Zitat

Ich bin nicht der Messias.
Ich sage, du bist es, Herr. Und ich muss es wissen, denn ich bin schon einigen gefolgt.

https://bitbucket.org/bwbg

5

26.11.2013, 13:39

Der Konstruktor kann ja an 2 Stellen hängen bleiben: Bei der Initialisierung der Member und bei der Ausführung des Rumpfes. Mir wäre keine Möglichkeit bekannt, Exceptions in der Initialisierungsliste zu fangen, wobei das ja im Zweifelsfalle nützlich sein könnte, um bessere Fehlermeldungen zu liefern. Vielleicht kennt da ja jemand ne Möglichkeit?
Im Rumpf selber kann man natürlich try-Blöcke einbauen. Die Frage ist, ob man deshalb Initialisierungslisten nicht benutzen sollte, nur um einen Fehler besser abzufragen (eine echte Fehlerbehandlung wird man wohl eh in den seltensten Fällen machen, aber man könnte zumindest eine andere Exception mit mehr Infos werfen).

Um bwbg Aussage zu erweitern: Der Destruktor des aktuellen Objektes (das, das gerade konstruiert werden soll) wird nicht aufgerufen, aber die Destruktoren aller Memberobjekte schon. Zumindest solange diese schon fertig sind, wenn die Initialisierungsliste beim 4. von 5 Objekten eine Exception bekommt, werden die Destruktoren der ersten 3 Member aufgerufen (da diese ja schon komplett fertig sind). C++ garantiert, dass der Destruktor jedes Objektes aufgerufen wird. (wobei man beachten muss, dass es eben im Konstruktor nicht gar nicht existiert, weil es gerade erst gebaut wird - also macht ein Destruktoraufruf auch keinen Sinn).


Also: Du kannst bad_alloc Exceptions im Konstruktorrumpf fangen. Und eine Fehlerbehandlung machen. Lustig wird es natürlich, wenn der Speicher wirklich schon komplett voll ist und nicht genügend übrig ist, um noch irgendwo eine Fehlermeldung zu speichern. Ich würde daher auch sagen, dass man das Programm ruhig mit einer Exception abstürzen lassen kann.
Lieber dumm fragen, als dumm bleiben!

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

6

26.11.2013, 13:44

Der Konstruktor kann ja an 2 Stellen hängen bleiben: Bei der Initialisierung der Member und bei der Ausführung des Rumpfes. Mir wäre keine Möglichkeit bekannt, Exceptions in der Initialisierungsliste zu fangen, wobei das ja im Zweifelsfalle nützlich sein könnte, um bessere Fehlermeldungen zu liefern. Vielleicht kennt da ja jemand ne Möglichkeit?
Ich glaube das geht absichtlich nicht. Exceptions im Konstruktor fangen ist eben nicht gewollt, wenn ich mich richtig erinnere. RAII und so... das sollte von allein tun.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

7

26.11.2013, 13:47

Wenn man Ausnahmen in der Initliaisierungsliste behandeln möchte, kann man nur eine Hilfsmethode schreiben, die das zu initlialisierende Objekt zurückgibt.
Falls die Hilfsmethode nicht statisch ist, gibt der Compiler möglicherweise eine Warnung aus, die man aber getrost ignorieren kann, solange man nicht auf uninitialisierte Member zugreift.

8

26.11.2013, 13:51

Hey, das ist eine coole Idee :)
Und man kann auch einfach eine "Modul-lokale" Funktion benutzen (denn wie der C'tor initialisiert ist ein Implementierungsdetail, und es gibt eigentlich keinen Grund dafür das Klasseninterface, also die Headerdatei der Klasse zu erweitern).
Lieber dumm fragen, als dumm bleiben!

9

26.11.2013, 14:38

Hier sollte man beachten, dass das Objekt im Falle einer Ausnahme nicht existiert und der Destruktor nicht aufgerufen wird. Alle angeforderten Ressourcen müssen daher im Konstruktor freigegeben werden.

Das ist so allgemein nicht mehr gültig (Stichwort: Delegating Constructors). Der Destruktor wird aufgerufen, sobald ein Konstruktor erfolgreich beendet wurde.
"Theory is when you know something, but it doesn’t work. Practice is when something works, but you don’t know why. Programmers combine theory and practice: Nothing works and they don’t know why." - Anon

10

15.12.2013, 17:10

Der Konstruktor kann ja an 2 Stellen hängen bleiben: Bei der Initialisierung der Member und bei der Ausführung des Rumpfes. Mir wäre keine Möglichkeit bekannt, Exceptions in der Initialisierungsliste zu fangen, wobei das ja im Zweifelsfalle nützlich sein könnte, um bessere Fehlermeldungen zu liefern. Vielleicht kennt da ja jemand ne Möglichkeit?
Ich glaube das geht absichtlich nicht. Exceptions im Konstruktor fangen ist eben nicht gewollt, wenn ich mich richtig erinnere. RAII und so... das sollte von allein tun.
Ja richtig. Für bessere Fehlermeldungen gibt es durchaus die Möglichkeit von try-Blöcken in Initialisierungslisten:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
Foo::Foo()
try
  : a()
  , b()
{
  // Rumpf
} catch(std::bad_alloc const &) {
  cout << "Zu wenig Speicher zur Konstruktion eines Foo" << endl;
} catch(...) {
  cout << "irgendwas ist mit Foo schiefgegangen" << endl;
}
Die Ausnahme kann dabei zwar gefangen, aber nie *ab*gefangen werden: sie verlässt in jedem Fall den K'tor und kann nicht die Attribute verändern (damit RAII konsistent bleibt).

Werbeanzeige