2008-10-19 5 views
5

Angenommen, ich habe eine Struktur "s" mit einem int Zeigerelement Variable "i". Ich reserviere Speicher im Heap für i im Standardkonstruktor von s. Später in einem anderen Teil des Codes übergebe ich eine Instanz von s nach Wert an eine Funktion. Mache ich hier eine flache Kopie? Angenommen, ich habe keine Kopierkonstruktoren oder Zuweisungsoperatoren oder irgendetwas für s implementiert ... nur den Standardkonstruktor.Frage über seichte Kopie in C++

Antwort

8

Um zu verfolgen, was @ [don.neufeld.myopenid.com] sagte, ist es nicht nur eine flache Kopie, aber es ist entweder ein Speicherleck oder ein baumelnder Zeiger.

// memory leak (note that the pointer is never deleted) 
class A 
{ 
    B *_b; 
    public: 
    A() 
    : _b(new B) 
    { 
    } 
}; 

// dangling ptr (who deletes the instance?) 
class A 
{ 
    B *_b; 
    public: 
    A() 
    ... (same as above) 

    ~A() 
    { 
    delete _b; 
    } 
}; 

Um dies zu beheben, gibt es mehrere Methoden.

Implementieren Sie immer einen Kopierkonstruktor und operator = in Klassen, die Raw-Speicherzeiger verwenden.

class A 
{ 
    B *_b; 
    public: 
    A() 
    ... (same as above) 

    ~A() 
    ... 

    A(const A &rhs) 
    : _b(new B(rhs._b)) 
    { 
    } 

    A &operator=(const A &rhs) 
    { 
    B *b=new B(rhs._b); 
    delete _b; 
    _b=b; 
    return *this; 
}; 

Unnötig zu sagen, dies ist ein großer Schmerz und es gibt durchaus ein paar Feinheiten richtig zu machen. Ich bin mir nicht einmal ganz sicher, ob ich das hier gemacht habe und ich habe es ein paar Mal gemacht. Vergiss nicht, dass du alle Mitglieder kopieren musst - wenn du später ein paar neue hinzufügst, vergiss nicht, sie auch hinzuzufügen!

Machen Sie den Kopierkonstruktor und Operator = privat in Ihrer Klasse. Dies ist die Lösung "sperre die Tür". Es ist einfach und effektiv, aber manchmal über-schützend.

class A : public boost::noncopyable 
{ 
    ... 
}; 

Niemals rohe Zeiger verwenden. Dies ist einfach und effektiv. Es gibt viele Möglichkeiten:

  • Verwenden String-Klassen statt roh char Zeiger
  • Verwendung std :: auto_ptr boost :: shared_ptr boost :: scoped_ptr etc

Beispiel:

// uses shared_ptr - note that you don't need a copy constructor or op= - 
// shared_ptr uses reference counting so the _b instance is shared and only 
// deleted when the last reference is gone - admire the simplicity! 
// it is almost exactly the same as the "memory leak" version, but there is no leak 
class A 
{ 
    boost::shared_ptr<B> _b; 
    public: 
    A() 
    : _b(new B) 
    { 
    } 
}; 
+0

Ihr Zuweisungsoperator ist nicht ausnahmesicher. Sehen Sie sich die aktuelle Frage zu Kopier- und Ausnahmesicherheit an: http://stackoverflow.com/questions/214891/checklist-for-wrice-copy-constuctor-and-assignment-operator-in-c#214966 –

+0

Doh, ok, das habe ich behoben . Sie sehen, was ich meine, es ist ein Schmerz und schwer zu bekommen, dann huh –

+0

Der beste Weg, um den Kopierkonstruktor und Operator = privat zu machen, ist von boost :: nicht kopierbar zu erben. Sie sollten das für jede einzelne Klasse tun, wenn Sie nicht sicher sind, dass es kopierbar sein wird. – CesarB

5

Ja, das ist eine flache Kopie. Sie haben nun zwei Kopien von s (eine im Aufrufer, eine im Stapel als Parameter), die jeweils einen Zeiger auf denselben Speicherblock enthalten.

2

Sie haben zwei Kopien der s Struktur, von denen jede ihre eigenen i Zeiger haben, aber beide i Zeiger den gleichen Wert haben auf die gleiche Adresse im Speicher zeigt - also ja, es wird eine flache Kopie sein .