Angenommen, ich habe den folgenden Konstruktor in einer C++-Klasse:
MyClass::MyClass()
{
char* buffer = malloc(100);
if (0 != someD3DXCallThatCanFail(..., buffer, ...))
{
free(buffer);
throw MyException(L"some message");
}
char* buffer2 = malloc(200);
if (0 != anotherD3DCallThatCanFail(..., buffer2, ...))
{
free(buffer);
free(buffer2);
throw MyException(L"another message");
}
.. more code here where buffer and buffer2 are still used
free(buffer);
free(buffer2);
}
EDIT: Ich hasse malloc/free und new/delete, aber leider muss ich Puffer für das Laden von Texturen verwenden, die dann an ID3D10ShaderResourceView, ID3D10Buffer, Vertexpuffer und dergleichen weitergegeben werden. Alle diese erfordern Zeiger auf einen Puffer.
Ich versuche, Ausnahmen zu verwenden, anstatt Fehlercodes zurückzugeben. Außerdem möchte ich Puffer erstellen, wenn sie benötigt werden, und sie sofort freigeben, wenn sie nicht mehr benötigt werden.
Was jedoch unschön aussieht, ist, dass ich im Falle von Fehlern, egal ob ich Fehlercodes zurückgebe oder Ausnahmen werfe, immer noch daran denken sollte, jeden Puffer zu bereinigen, der bis zu diesem Punkt erstellt wurde. Wenn ich 10 Puffer und 10 mögliche Fehlerpunkte habe, muss ich free() 100 Mal aufrufen (und bei jedem Fehler daran denken, jeden Puffer zu löschen).
Nehmen wir nun an, dass ich oder, schlimmer noch, mein Kollege einige logische Änderungen vornehmen möchte und z. B. irgendwo in der Mitte einen weiteren Puffer einfügt. Nun müsste er alle Fehler, die im Rest der Methode auftreten können, durchsehen und an jeder solchen Stelle free() für diesen Puffer hinzufügen. Wenn er es eilig hat, kann er leicht ein paar solcher Stellen übersehen, und Sie haben ein Speicherleck.
Auch dies bläht den Code immens auf.
Das Schlüsselwort finally würde dieses Problem in Java oder C# lösen. Unabhängig davon, an welcher Stelle des Codes die Ausnahme auftrat, würde ich all diese Puffer in "finally" aufräumen (was übrigens bei der Garbage Collection nicht nötig wäre). In C++ muss ich, soweit ich weiß, möglicherweise eine Membervariable für solche Puffer erstellen und im Destruktor sicherstellen, dass die Puffer aufgeräumt werden. Sieht für mich auch ziemlich hässlich aus, da eine Mitgliedsvariable mit dem Namen "pBuffer", selbst eine private, nur Müll ist, da sie nur in der einen Methode (in diesem Fall der Konstruktor) verwendet wird und den Rest der Zeit immer NULL sein wird.
Das muss ein häufiges Problem sein, aber ich habe mit der Suche keine Antwort gefunden. Danke!