4 Stimmen

Beste Strategie für die manuelle Speicherverwaltung unter Verwendung von intelligenten Zeigern?

Gibt es eine empfohlene Strategie für den Umgang mit externen Bibliotheken, die manuell verwaltete Rohzeiger erwarten? Zum Beispiel eine Methode, die einen Vektor von Zeigern erfordert:

ALibraryFunc(std::vector p);

Normalerweise würden Sie Ihren Vektor etwa so erstellen:

std::vector myVec;
for(...)
{
    myVec.push_back(new ALibraryData(args));
}
//und dann
ret = ALibraryFunc(myVec);
//und dann
for(auto &a:myVec)
{
    delete a;
}
myVec.clear();

Ich würde viel lieber intelligente Zeiger verwenden, aber die Bibliothek akzeptiert sie nicht. Das lässt mich fragen, ob so etwas eher stinkig ist als es manuell zu tun:

std::vector> myVecUP;
std::vector myVec;
for(...)
{
    myVecUP.push_back(std::make_unique(args));
    myVec.push_back(myVecUP.back().get());
}
//und dann
ret = ALibraryFunc(myVec);
myVec.clear();
myVecUP.clear();

Die zweite Version scheint sicherer im Falle von Ausnahmen oder Fehlern zu sein, aber sie birgt das Risiko von hängenden Zeigern. Übersehe ich hier etwas Offensichtliches? Was würden Sie tun?

5voto

Wojtek Surowka Punkte 19781

Sie können eine kleine Klasse deklarieren, die den Vektor von Rohzeigern besitzt und die Zeiger im Destruktor löscht:

struct VecOwner {
 std::vector vec;
 VecOwner()
 {
     // füllen Sie den Vektor hier
 }
 ~VecOwner()  
 {
   for(auto &a:vec)
     delete a;
   vec.clear();
 }
};

Sie sollten in der Lage sein, die Klasse an allen Stellen wiederzuverwenden, an denen Sie die Bibliothek verwenden.

3voto

Khurshid Punkte 2634

Sie können das 'Scope-Exit'-Idiom verwenden:

//Öffnen des Bereichs
{
    std::vector myVec;
    ////////////////////////////////////////
    struct MyVecRAIICleaner{ 
      std::vector * myVecPtr;
      ~MyVecRAIICleaner(){ 
        if (myVecPtr) {
         for(auto& a: *myVecPtr)
            delete a;
         myVecPtr->clear();
        }
       }
    } myRAIICleaner = {&myVec};
    ////////////////////////////////////////
   for(...)
   {
       myVec.push_back(new ALibraryData(args));
    }
    //und dann
    ret = ALibraryFunc(myVec);

    /** Sie benötigen den untenstehenden Code nicht. */
    ////und dann 
    //for(auto &a:myVec)
    //{
    //    delete a;
    //}
    //myVec.clear();

}// Bereichsende 

EDIT:
Es tut mir leid, aber die Antwort von Wojtek Surowka ist nicht ausnahmesicher oder erfordert einen zusätzlichen Try-Catch-Block im Konstruktor.

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