2010-02-27 6 views
5

definieren Ich lese effektiv C++ in Punkt 5, erwähnt zwei Fälle, in denen ich den Kopierzuweisungsoperator selbst definieren muss. Der Fall ist eine Klasse, die Konstanten und Referenzmitglieder enthält.Wann sollte ich meinen eigenen copy ctor und Zuweisungsoperator

Ich schreibe um zu fragen, was ist die allgemeine Regel oder der Fall, in dem ich meinen eigenen Kopierkonstruktor und Zuweisungsoperator definieren muss?

Ich würde auch gerne wissen, wann ich meinen eigenen Konstruktor und Destruktor definieren muss.

Vielen Dank!

+0

Soweit ich verstehe (und handle) - eine zusätzliche gute Praxis (nicht die anderen Antworten hier zurückziehen) wird folgen "Die Regel der drei": https://stackoverflow.com/q/4172722/1971003 –

Antwort

5

Sie müssen Ihren eigenen Kopie Konstruktor und Zuweisungsoperator (und in der Regel Standard-Konstruktor zu) erstellen, wenn:

  • Sie mögen Ihr Objekt kopiert oder zugewiesen werden, oder in einen Standard-Container wie vector
  • Der Standardkopiekonstruktor und der Zuweisungsoperator werden nicht die richtige Sache machen.

Betrachten Sie den folgenden Code ein:

class A; // defined elsewhere 
class B { 
private: 
    A *my_very_own_a; 
}; 

Wenn Sie die automatische Copykonstruktor eine B kopieren lassen, wird es den A * Zeigerwert über kopieren, so dass die Kopie zeigt auf die gleiche A Instanz wie die Original. Aber ein Teil des Designs dieser Klasse ist, dass jede B ihre eigene A hat, so dass der automatische Kopierkonstruktor diesen Vertrag gebrochen hat. Sie müssen also einen eigenen Kopierkonstruktor schreiben, der einen neuen A für den neuen B erstellt, auf den Sie zeigen können.

Allerdings betrachten diesen Fall:

class A; // defined elsewhere 
class B { 
private: 
    A *shared_reference_to_a; 
}; 

Hier wird jeder B enthält einen Zeiger auf ein A, aber die Klasse Vertrages verlangen keinen eindeutigen A für jeden B. Also könnte der automatische Kopierkonstruktor das Richtige hier tun.

Beachten Sie, dass beiden Beispiele sind der gleiche Code, aber mit unterschiedlichen Konstruktionsabsicht. Ein Beispiel für die erste Situation könnte B == Dialogfeld, A == Schaltfläche sein. Wenn Sie eine Kopie eines Dialogfelds erstellen, benötigt es wahrscheinlich auch eine Kopie aller Inhalte.

Ein Beispiel für die zweite könnte B == Dialogfeld, A == Verweis auf Fenstermanager sein. Wenn Sie ein Dialogfeld kopieren, existiert die Kopie wahrscheinlich im selben Fenstermanager wie das Original.

3

Der standardmäßige Kopierkonstruktor bewirkt oft, dass zwei Objekte auf einen gemeinsamen Speicherbereich "zeigen". Dies liegt daran, dass der Standard-Kopierkonstruktor nur eine Memberwise-Zuweisung ist. Wenn Sie also ein Zeiger Mitglied haben, kann dies Sie in Schwierigkeiten geraten

CClass::CClass(const CClass& src) 
    { 
     // these two point to the same place in memory now 
     // you really aught to allocate new memory 
     m_ptr = src.m_ptr; 

     // not a big deal for members that aren't "pointing" elsewhere 
     // this copy works great 
     m_int = src.m_int; 
    } 

Sie im Wesentlichen wollen nicht in einer Situation enden, wo zwei Instanzen „zeigt auf“ den gleichen Platz im Speicher. Dies kann passieren, wenn Sie Zeiger als Elemente haben, die auf dynamisch zugewiesenen Speicher verweisen. Dies kann auch mit Referenzen geschehen, die sich auf etwas außerhalb der Klasse selbst beziehen. Dies kann bei Dateihandles auftreten, bei denen Sie möglicherweise eine neue Datei duplizieren/erneut öffnen müssen.

In der Tat ist der letztere Fall wahrscheinlich am einfachsten zu konzipieren. Stellen Sie so, als ob Ihre 2 C++ - Objekte eine Protokolldatei hätten. Ohne einen korrekt funktionierenden Kopierkonstruktor könnten sie sich beide in derselben Datei anmelden. Was passiert, wenn in den Klassen destructor die Datei geschlossen wird? Nun, das zweite C++ Objekt wird seine Protokolldatei unter sich geschlossen haben. Eine Lösung wäre, einen Kopierkonstruktor zu erstellen, der eine neue Datei für die neu erstellte Instanz erstellt. Wenn also das erste C++ Objekt verschwindet, nimmt es die Protokolldatei des 2. C++ Objekts nicht mehr mit. Sie haben 2 unabhängige Protokolldateien, sie können sich nicht gegenseitig stören.

Dieses Beispiel kann auf dynamischen Speicher erweitert werden. Ohne einen Kopierkonstruktor haben Sie nur 2 Zeiger, die auf dieselbe Adresse zeigen. Wenn der Destruktor von einem diesen Speicher löscht, erkennt der andere möglicherweise nicht, dass der Speicher, auf den er zeigt, verschwunden ist. Genauso wichtig ist es wahrscheinlich, dass Sie nicht wollen, dass ein Objekt in das Mitglied des anderen Objekts schreibt :).

Verwandte Themen