Klassenglobales Arrays (als Membervariable)
-
groovemaster schrieb:
Caipi schrieb:
Foo::Foo(const int& s) { iNumNotes = s; notes = new string[iNumNotes]; iCountNotes = new int[iNumNotes]; }
Aber bitte schön brav die Initialisierungsliste hier benutzen. Und primitive Typen werden hier normalerweise by-value übergeben.
Sorry, aber was ist eine Initialisierungsliste? Ist das das gleiche wie Elementinitialisierer?
Caipi
-
Foo::Foo(const int s) : iNumNotes(s) //<-- Initialisierungliste { notes = new string[iNumNotes]; iCountNotes = new int[iNumNotes]; }
Die Initialisierungliste dient dazu, konstante Variablen zu initialisieren (ist der einzige Weg dies zu tun) oder Objekte die keinen Default-Ctor haben (bin mir da grade unsicher) und gilt auch für Referenzen.
Edit: Und ja, das ist das gleiche. (Zumindest hab ich es auch so gelernt)
-
Du kannst durchaus alles in der Initialisierungsliste machen
Foo::Foo(int s) : iNumNotes(s) , notes(new string[iNumNotes]) , iCountNotes(new int[iNumNotes]) { }
Wichtig dabei ist nur die Rangfolge. Und die hängt iirc nicht von der Initialisierungsliste ab, sondern von der Klassendefinition. Man sollte diese deshalb wie folgt ändern
class Foo { private: int iNumNotes; std::string* notes; int* iCountNotes; // [...] };
-
Danke euch beiden, wieder was gelernt ...
Caipi
-
groovermaster: Dein Code mit der Initialisierungsliste ist nicht exception-sicher. Wenn das erste new funktioniert und das zweite ein bad-alloc wirft dann haste ein Resource-leak.
mit einem std::vector verschwindet das Problem, das ist hier also vorzuziehen. Alternativ könnte man natürlich auch mit try-catch das ganze absichern... dann aber wieder nur im Rumpf des Konstruktors.
-
Ein klassenglobales Array funktioniert eigentlich nicht viel anders als ein normales.
// Header class Klasse { static const int iNumNotes = 11; static int iCountNotes[iNumNotes]; static std::string Notes[iNumNotes]; ... }; // Implementierung int Klasse::iCountNotes[iNumNotes] = { 0 }; std::string Klasse::Notes[iNumNotes] = { "1.0","1.3","1.7", "2.0","2.3","2.7", "3.0","3.3","3.7", "4.0","5.0" };
-
Jester schrieb:
groovermaster: Dein Code mit der Initialisierungsliste ist nicht exception-sicher. Wenn das erste new funktioniert und das zweite ein bad-alloc wirft dann haste ein Resource-leak.
Was interessieren mich Memory Leaks, wenn der Speicher 'eh nicht ausreicht?
Ne, aber mal im ernst. Bekomm ich Exception Probleme, weil die Speicherreservierung in der Initialisierungsliste steht? Dh, wenn ich das im Rumpf des ctors machen würde, wäre alles ok? Oder hast du das anders gemeint?
-
Jein.
Das Problem ist: das erste new klappt, das zweite wirft bad_alloc, dann haste keine Chance das erste noch wieder freizugeben.
Im Rumpf könntest Du halt um das zweite ein try-catch drummachen und im catch das erste freigeben. Besser ist es allerdings mit smart-pointern oder ähnlichem oder hier speziell eben vector RAII-mäßig die Ressourcen managen zu lassen. Dann muß man sich um sowas nicht kümmern.
So klarer?
-
Aaah, so langsam machts klick. Das Problem ist eigentlich ein grundsätzliches. Im Funktionsrumpf hast du aber die Chance mittels try/catch 'ne Exception abzufangen, in der Initialisierungsliste hast du die nicht.
Naja, ich denke ich kann damit im Moment leben. Normalerweise greife ich auch auf entsprechende Container zurück. Aber wenns dennoch mal roher Speicher sein muss und es daran fehlt, dann ist imo 'eh nix mehr zuverlässig zu retten.
-
Im Prinzip hast Du die Abfangmöglichkeit schon. Stichwort: function-try-blocks. Aber auch die nützen Dir nichts. Letztlich ist es das Gleiche wie wenn Du in einer Anweisung mehrere dynamische Ressourcen auf einmal anforderst.
MeineKlasse meineInstanz(new X, new Y);
ist egal wie toll das Management von MeineKlasse ist einfach unsicher. Wenn das erste gelingt und das zweite fehlschlägt, dann ist nichts mehr zu machen.