3 Stimmen

Speicherverfälschung in einer kleinen ref-counted Pufferklasse

Ich habe eine einfache referenzzählende Klasse, die einen Speicherbuffer enthält. Es sieht so aus:

#include 

template
struct buffer
{
    // Erstellt einen Puffer der Länge n
    buffer(unsigned n) : rc(*(new unsigned(1))), data(new T[n]) { }

    buffer(const buffer & rhs) : rc(++rhs.rc), data(rhs.data) { }

    buffer& operator=(buffer rhs)
    {
        std::swap(rc, rhs.rc);
        std::swap(data, rhs.data);
        return *this;
    }

    ~buffer()
    {
        if (--rc == 0) {
            delete [] data;
            delete (&rc);
        }
    }

private:
    mutable unsigned & rc;
    T * data;
};

int main() {
    typedef buffer numbers;
    numbers n1(10);
    numbers n2(20);
    numbers n3(30);
    n1 = n2 = n3 = n2;
}

Ich sehe keinen Fehler im Code. Allerdings beschweren sich Visual Studio und valgrind über Speicherkorruption.

Ich habe diesen Code jetzt viel zu lange angestarrt. Kann jemand den Fehler erkennen?

13voto

R. Martinho Fernandes Punkte 217895

Ein Problem ist, dass wenn du swap(rc, rhs.rc); machst, tauschst du tatsächlich die Inhalte der Zählungen aus, nicht die Verweise.

Stell dir die Situation vor:

Before

Wenn du swap(rc, rhs.rc); machst, bleiben die Verweise auf die Zählungen gleich, und die Zählungen selbst werden ausgetauscht. Das ist das Ergebnis nach den beiden Austauschen:

After

Die Pufferzeiger sind korrekt, aber die Verweise auf die Zählungen beziehen sich immer noch auf die gleichen unsigned Objekte. Der Wert dieser Objekte wurde jedoch ausgetauscht. Beachte, wie der Puffer B aus Sicht eines der ausgetauschten Objekte eine Referenzanzahl von 2 hat und aus Sicht des unteren Objekts eine Referenzanzahl von 1.

Du musst Zeiger für die Zählung verwenden und die Zeiger austauschen, nicht die Inhalte.

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