2 Stimmen

Freigeben von lokalen Puffern beim Auslösen von Ausnahmen in C++

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!

8voto

Stuart Golodetz Punkte 19634

Hören Sie auf, den Speicher manuell zu verwalten, und Sie werden diese Art von Problemen nicht mehr haben. Verwenden Sie etwas wie std::vector<char> .

Alternativ können Sie auch etwas wie Boosts shared_array aber das ist zu viel des Guten für das, was Sie hier tun wollen:

http://www.boost.org/doc/libs/1_41_0/libs/smart_ptr/shared_array.htm

Der allgemeinere Punkt, der hier angesprochen werden soll, ist, dass Sie das RAII-Idiom verwenden sollten - das heißt, wenn Sie Ressourcen erwerben, speichern Sie sie in einer Instanz einer Klasse, deren Destruktor sie wieder freigibt. Dann jedoch wird eine Instanz

S

h

4voto

thiton Punkte 35046

Die kanonische Antwort ist das Prinzip der "Resource Acquisition Is Initialization" (RAII) und der intelligenten Zeiger. Sie erstellen eine Klasseninstanz auf dem Stack, die den Speicher in ihrem Destruktor freigibt, z.B. boost::scoped_ptr .

2voto

BЈовић Punkte 59375

I r :

MyClass::MyClass()
{
    std::vector<char> buffer(100);
    if (0 != someD3DXCallThatCanFail(...))
    {
        throw MyException(L"some message");
    }
    std::vector<char> buffer2c(200);
    if (0 != anotherD3DCallThatCanFail(...))
    {
        throw MyException(L"another message");
    }
    .. more code here 
}

1voto

Victor Sorokin Punkte 11645

Verwenden Sie hierfür den idiomatischen C++-Ansatz: RAII . Diese Wikipedia-Seite enthält ein C++-Beispiel.

1voto

Steve Townsend Punkte 52288

Suchen Sie erneut nach "C++ smart pointers". Sie benötigen einen ausnahmesicheren Wrapper für den Speicher anstelle von rohen malloc die, wie Sie festgestellt haben, viel Kopfzerbrechen bereitet und im Übrigen besser ersetzt werden kann durch operator new jetzt schreiben Sie C++ und nicht C-Code.

Vorherige Antwort aquí deckt diesen Bereich ab.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X