2010-07-16 8 views
26

Ich arbeite an einem Codeabschnitt, der viele mögliche Fehlerpunkte aufweist, die dazu führen, dass die Funktion vorzeitig beendet wird. Die Bibliotheken, mit denen ich interagiere, erfordern, dass C-artige Arrays an die Funktionen übergeben werden. Anstatt also an jedem Ausgangspunkt auf den Arrays löschen Aufruf, mache ich das:Können Sie ein shared_ptr für RAII von C-artigen Arrays verwenden?

void SomeFunction(int arrayLength) 
{ 
    shared_ptr<char> raiiArray(new char[arrayLength]); 
    pArray = raiiArray.get(); 

    if(SomeFunctionThatRequiresCArray(pArray) == FAILED) { return; } 

    //etc. 
} 

Ich wollte unique_ptr verwenden, aber meine aktuellen Compiler nicht unterstützt und der Referenzzähler Kopf nicht wirklich wichtig in diesem Fall.

Ich frage mich nur, ob jemand irgendwelche Gedanken über diese Praxis hat, wenn es mit Legacy-Code Schnittstellen.

UPDATE Ich habe ganz vergessen über die shared_ptrdelete statt delete [] aufrufen. Ich habe gerade keine Speicherlecks gesehen und beschlossen, damit zu gehen. Ich habe nicht einmal daran gedacht, einen Vektor zu verwenden. Seit ich mich in letzter Zeit mit C++ beschäftigt habe, denke ich, dass ich einen Fall von "Wenn das einzige Werkzeug, das du hast, ein Hammer ist, sieht alles wie ein Nagel aus." Syndrom. Danke für die Rückmeldung.

UPDATE2 Ich dachte, ich würde die Frage ändern und eine Antwort geben, um es ein wenig wertvoller für jemanden zu machen, der den gleichen Fehler macht wie ich. Zwar gibt es Alternativen wie scoped_array, shared_array und vector, können Sie einen shared_ptr verwenden Umfang eines Arrays zu verwalten (aber danach habe ich keine Ahnung, warum ich wollen würde):

template <typename T> 
    class ArrayDeleter 
    { 
    public: 
     void operator() (T* d) const 
     { 
      delete [] d; 
     } 
    }; 

void SomeFunction(int arrayLength) 
    { 
     shared_ptr<char> raiiArray(new char[arrayLength], ArrayDeleter<char>()); 
     pArray = raiiArray.get(); 

     if(SomeFunctionThatRequiresCArray(pArray) == FAILED) { return; } 

     //etc. 
    } 
+1

Nitpicking: [[shared_ptr]] funktioniert nicht korrekt auf dynamischen Array-Zeigern. Verwenden Sie [[scoped_array]] oder [[shared_array]]. – rwong

Antwort

27

Verwenden Sie nicht shared_ptr oder scoped_ptr, um Zeiger auf dynamisch zugewiesene Arrays zu halten. shared_ptr und scoped_ptr verwenden delete ptr;, um aufzuräumen, wenn der Zeiger nicht mehr referenziert wird oder den Gültigkeitsbereich verlässt, was zu undefiniertem Verhalten in einem dynamisch zugewiesenen Array führte. Verwenden Sie stattdessen shared_array oder scoped_array, die bei der Zerstörung delete[] ptr; korrekt verwenden.

Um Ihre Frage zu beantworten, verwenden Sie scoped_array, wenn Sie nicht den intelligenten Zeiger übergeben werden, da es weniger Overhead als shared_array hat.

Alternativ verwenden Sie std::vector als Array-Speicher (Vektoren haben eine zusammenhängende Speicherzuweisung garantiert).

+7

Standardmäßig verwenden shared_ptr und scoped_ptr delete ptr, aber Sie können eine eigene Löschfunktion oder einen Funktor angeben. – George

5

ist es boost::scoped_ptr dafür.

+7

scoped_array in diesem Fall –

+0

Ja, sicher, sie sind beide da. Vielen Dank. –

15

Verwenden Sie boost::scoped_array oder noch besser std::vector, wenn Sie mit einem Array zu tun haben.

3

Diese

shared_ptr<char*> raiiArray(new char[arrayLength]); 

ist keine gute Praxis, aber nicht definiertes Verhalten verursacht, wie Sie mit Operator new[], zuteilen aber shared_ptr verwendet operator delete den Speicher freizugeben. Das richtige zu verwenden ist boost::shared_array oder fügen Sie einen benutzerdefinierten Deleter hinzu.

7

Ich empfehle sehr, einfach eine std::vector zu verwenden. Elemente in vectors sind auf dem Heap zugeordnet und werden gelöscht, wenn die vector außerhalb des Gültigkeitsbereichs liegt, wo auch immer Sie die Funktion beenden.

Um eine vector an Legacy-Code zu übergeben, der C-artige Arrays erfordert, übergeben Sie einfach &vectorName[0]. Die Elemente sind garantiert zusammenhängend im Speicher.

+0

Stellen Sie sicher, dass der Vektor nicht leer ist, bevor Sie '& vectorName [0]' oder '& vectorName.front()' verwenden, da dieser für einige Implementierungen nicht definiert ist oder das Verhalten bestätigt. – AshleysBrain

6

Einige Bemerkungen für ++ 11 Benutzer C:

Für shared_ptr gibt in C++ 11 ein Standard deleter für Array-Typen definiert in <memory> und Standard kompatibel ist (den endgültigen Entwurf wrt), so kann es verwendet werden ohne zusätzliche Phantasie Löscher für solche Fälle:

std::shared_ptr<char> raiiArray(new char[arrayLength], std::default_delete<char[]>()); 

unique_ptr in C++ 11 eine partielle Spezialisierung hat mit new[] und delete[] zu beschäftigen. Aber es hat leider kein gemeinsames Verhalten. Es muss ein guter Grund sein, dass es keine solche Spezialisierung für shared_ptr gibt, aber ich habe nicht danach gesucht, wenn Sie es wissen, teilen Sie es bitte.

+1

Laut [dieser SO-Antwort] (http://Stackoverflow.com/a/8947700/1094609) ist der letzte Grund, warum es keine Array-Spezialisierung für 'shared_ptr' gibt, dass" [T] hier war nie ein tatsächlicher schriftlicher Vorschlag im Vordergrund der LWG dazu. " –