18 Stimmen

Checkliste zum Schreiben von Kopierkonstruktoren und Zuweisungsoperatoren in C++

Bitte erstellen Sie eine Liste der Aufgaben, die ein Kopierkonstruktor und ein Zuweisungsoperator in C++ erfüllen müssen, um Ausnahmesicherheit zu gewährleisten, Speicherlecks zu vermeiden usw.

15voto

Luc Hermitte Punkte 30868

Vergewissern Sie sich zunächst, dass Sie die Kopie wirklich benötigen. In den meisten Fällen ist dies nicht der Fall, und daher ist die Deaktivierung beider Optionen der richtige Weg.

In diesem Fall sollten Sie den Zuweisungsoperator deaktivieren, einen (geschützten?) Kopierkonstruktor schreiben und eine virtuelle clone()-Funktion zur Verfügung stellen.

Andernfalls, wenn Sie eine Wertklasse schreiben, sind Sie zurück im Land der orthogonalen kanonischen Form von Coplien. Wenn Sie ein Mitglied haben, das nicht trivial kopiert werden kann, müssen Sie einen Kopier-Konstruktor, einen Destruktor, einen Zuweisungsoperator und einen Standard-Konstruktor bereitstellen. Diese Regel kann verfeinert werden, siehe zum Beispiel: Das Gesetz der großen Zwei

Ich würde auch empfehlen, einen Blick auf C++ FAQ zu Zuweisungsoperatoren und bei der Redewendung zum Kopieren und Austauschen und bei GOTW .

0 Stimmen

Ich dachte, man nennt es die 4er-Regel.

0 Stimmen

AFAIK stammt es aus dem Buch von Jim Coplien, daher der Name - es gilt übrigens nur für Wertklassen. Manche nennen sie auch die Vierer-Regel. Es gibt (gab?) auch Erklärungen zu /Rule of Big Three/ in C++ FAQ lite (ich kann sie nicht mehr finden). Und sie kann dank RAII auf zwei reduziert werden.

2 Stimmen

Schützen Sie sich auch vor Selbstzuweisung im Zuweisungsoperator.

4voto

Martin York Punkte 245363

Die vom Compiler erzeugten Versionen funktionieren in den meisten Situationen.

Sie müssen ein bisschen mehr über das Problem nachdenken, wenn Ihr Objekt einen RAW-Zeiger enthält (ein Argument dafür, keine RAW-Zeiger zu haben). Sie haben also einen RAW-Zeiger, die zweite Frage ist, ob Sie Eigentümer des Zeigers sind (wird er von Ihnen gelöscht)? Wenn ja, dann müssen Sie die 4er-Regel anwenden.

Der Besitz von mehr als 1 RAW-Zeiger wird immer schwieriger, richtig zu tun (Die Zunahme der Komplexität ist auch nicht linear [aber das ist eine Beobachtung und ich habe keine wirklichen Statistiken, um diese Aussage zu unterstützen]). Wenn Sie also mehr als 1 RAW-Zeiger haben, denken Sie darüber nach, jeden in seine eigene Klasse zu verpacken (eine Form von Smart Pointer).

4er-Regel: Wenn ein Objekt der Eigentümer eines RAW-Zeigers ist, müssen Sie die folgenden 4 Mitglieder definieren, um sicherzustellen, dass Sie die Speicherverwaltung korrekt handhaben:

  • Konstrukteur
  • Konstrukteur kopieren
  • Zuweisung Operator
  • Zerstörer

Wie Sie diese definieren, hängt von der jeweiligen Situation ab. Aber es gibt Dinge, auf die man achten sollte:

  • Standardkonstruktion: Zeiger auf NULL setzen
  • Kopieren Sie den Konstruktor: Verwendung des Kopier- und Tausch-Ideals, um die "starke Ausnahmegarantie" zu gewährleisten
  • Zuweisungsoperator: Prüfung auf Zuweisung an sich selbst
  • Zerstörer: Schutz vor Ausnahmen, die sich aus dem Destruktor heraus ausbreiten.

0 Stimmen

"Die vom Compiler erzeugten Versionen funktionieren in den meisten Situationen." - je nachdem, welche Art von Programmierung Sie betreiben. Selbst wenn alles intelligente Zeiger sind, die sich mit Ressourcenverfolgung und Ausnahmeproblemen befassen, ist eine oberflächliche Kopie möglicherweise nicht das, was Sie semantisch wollen.

1voto

ugasoft Punkte 3552

Versuchen Sie, dies zu lesen.

http://www.icu-project.org/docs/papers/cpp_report/the_anatomy_of_the_assignment_operator.html

ist eine sehr gute Analyse von Assignment operator

0 Stimmen

Das ist eine typische Frage, die ich in einem Vorstellungsgespräch stellen würde. Ich sehe jedoch eine falsche Annahme: dass die meisten Objekte kopierbar sein müssen. "Jedes Objekt in einem gut konzipierten C++-System hat einen Standardkonstruktor, einen Kopierkonstruktor und einen Zuweisungsoperator." Dieser Satz bezieht sich auf wertbasierte Objekte, nicht auf Entitäten.

-2voto

Nazgob Punkte 8384

Ich habe keine Ahnung, ob hier Ausnahmen sicher sind, aber ich gehe diesen Weg. Stellen wir uns vor, es ist eine Vorlage Array Wrapper. Hoffe, es hilft :)

Array(const Array& rhs)
    {
        mData = NULL;
        mSize = rhs.size();
        *this = rhs;
    }

    Array& operator=(const Array& rhs)
    {
        if(this == &rhs)
        {
            return *this;
        }

        int len = rhs.size();

        delete[] mData;

        mData = new T[len];

        for(int i = 0; i < len; ++i)
        {
            mData[i] = rhs[i];
        }

        mSize = len;

        return *this;
    }

0 Stimmen

Dieser Code ist nicht ausnahmesicher. Allokieren Sie immer vor der Freigabe!

0 Stimmen

Nein, ist es nicht. Ich hatte keine Probleme mit Ausnahmen sicheren Code, so dass ich nie eine Chance, es zu üben hatte. Diese oben ist ofc nur Snipper, normalerweise verwenden Sie STL-Container. Bitte posten Sie Ihr Snippet, ich würde gerne einen Blick auf sie zu nehmen.

0 Stimmen

In den Links, die ich in meiner Antwort angegeben habe, finden sich zahlreiche Auszüge. BTW, der Test, der die Selbstzuweisung verhindert, wird jetzt als Anti-Idiom betrachtet (jetzt, da Ausnahmen besser verstanden werden)

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