349 Stimmen

Aus der Dreier-Regel wird mit C++11 die Fünfer-Regel?

Also, nachdem ich dieser wunderbare Vortrag auf rvalue-Referenzen, dachte ich, dass jede Klasse von einem solchen "move constructor" profitieren würde, template<class T> MyClass(T&& other) bearbeiten und natürlich ein "move assignment operator", template<class T> MyClass& operator=(T&& other) wie Philipp in seiner Antwort darlegt, wenn es dynamisch zugewiesene Mitglieder hat oder allgemein Zeiger speichert. Genau wie Sie sollte haben einen Kopiersektor, einen Zuweisungsoperator und einen Destruktor, wenn die oben genannten Punkte zutreffen. Was denken Sie?

4voto

sellibitze Punkte 26706

Im Grunde ist es so: Wenn Sie keine Zugoperationen deklarieren, sollten Sie den Dreisatz einhalten. Wenn Sie eine move-Operation deklarieren, schadet es nicht, die Dreierregel zu "verletzen", da die Generierung von compiler-generierten Operationen sehr restriktiv geworden ist. Selbst wenn Sie keine Verschiebeoperationen deklarieren und die Dreierregel verletzen, wird ein C++0x-Compiler voraussichtlich eine Warnung ausgeben, falls eine spezielle Funktion vom Benutzer deklariert wurde und andere spezielle Funktionen aufgrund einer inzwischen veralteten "C++03-Kompatibilitätsregel" automatisch generiert wurden.

Ich denke, man kann mit Sicherheit sagen, dass diese Regel ein wenig an Bedeutung verliert. Das eigentliche Problem in C++03 ist, dass die Implementierung verschiedener Kopiersemantiken eine Benutzerdeklaration todos verwandte spezielle Funktionen, so dass keine von ihnen vom Compiler generiert wird (der sonst das Falsche tun würde). Aber C++0x ändert die Regeln für die Erzeugung spezieller Mitgliedsfunktionen. Wenn der Benutzer nur eine dieser Funktionen deklariert, um die Kopiersemantik zu ändern, wird der Compiler daran gehindert, die übrigen speziellen Funktionen automatisch zu generieren. Das ist gut, denn eine fehlende Deklaration verwandelt jetzt einen Laufzeitfehler in einen Kompilierungsfehler (oder zumindest in eine Warnung). Als C++03-Kompatibilitätsmaßnahme werden einige Operationen immer noch generiert, aber diese Generierung gilt als veraltet und sollte zumindest im C++0x-Modus eine Warnung erzeugen.

Aufgrund der eher restriktiven Regeln für compilergenerierte Spezialfunktionen und der C++03-Kompatibilität bleibt der Dreisatz der Dreisatz.

Hier sind einige Beispiele, die mit den neuesten C++0x-Regeln in Ordnung sein sollten:

template<class T>
class unique_ptr
{
   T* ptr;
public:
   explicit unique_ptr(T* p=0) : ptr(p) {}
   ~unique_ptr();
   unique_ptr(unique_ptr&&);
   unique_ptr& operator=(unique_ptr&&);
};

Im obigen Beispiel ist es nicht erforderlich, eine der anderen Sonderfunktionen als gelöscht zu deklarieren. Sie werden aufgrund der restriktiven Regeln einfach nicht erzeugt. Das Vorhandensein einer vom Benutzer deklarierten Verschiebeoperation deaktiviert die vom Compiler erzeugten Kopieroperationen. Aber in einem Fall wie diesem:

template<class T>
class scoped_ptr
{
   T* ptr;
public:
   explicit scoped_ptr(T* p=0) : ptr(p) {}
   ~scoped_ptr();
};

von einem C++0x-Compiler wird nun erwartet, dass er eine Warnung über möglicherweise vom Compiler erzeugte Kopieroperationen ausgibt, die das Falsche tun könnten. Hier ist der Dreisatz von Bedeutung und sollte eingehalten werden. Eine Warnung ist in diesem Fall völlig angemessen und gibt dem Benutzer die Möglichkeit, den Fehler zu beheben. Wir können das Problem durch gelöschte Funktionen beseitigen:

template<class T>
class scoped_ptr
{
   T* ptr;
public:
   explicit scoped_ptr(T* p=0) : ptr(p) {}
   ~scoped_ptr();
   scoped_ptr(scoped_ptr const&) = delete;
   scoped_ptr& operator=(scoped_ptr const&) = delete;
};

Die Dreierregel gilt also auch hier, einfach wegen der C++03-Kompatibilität.

3voto

CashCow Punkte 29849

Wir können nicht sagen, dass Regel 3 jetzt zu Regel 4 (oder 5) wird, ohne den gesamten bestehenden Code zu zerstören, der Regel 3 erzwingt und keine Form von Bewegungssemantik implementiert.

Die 3er-Regel besagt, dass man, wenn man eine Maßnahme durchführt, alle 3 Maßnahmen durchführen muss.

Es ist auch nicht bekannt, dass es einen automatisch generierten Zug geben wird. Der Zweck der "Regel der 3" ist, weil sie automatisch existieren und wenn Sie eine zu implementieren, ist es höchstwahrscheinlich die Standard-Implementierung der anderen beiden falsch ist.

2voto

Puppy Punkte 141483

Im allgemeinen Fall wurde aus der Dreierregel einfach die Fünferregel, wobei der Zuweisungsoperator und der Konstruktor für die Verschiebung hinzugefügt wurden. Allerdings nicht todos Klassen sind kopierbar und verschiebbar, manche sind nur verschiebbar, manche nur kopierbar.

0voto

zeitgeist Punkte 562

In einfachen Worten: Denken Sie daran.

Regel von 0 :

Classes have neither custom destructors, copy/move constructors or copy/move assignment operators.

3er-Regel : Wenn Sie eine benutzerdefinierte Version einer dieser Funktionen implementieren, implementieren Sie alle diese Funktionen.

Destructor, Copy constructor, copy assignment

Die 5er-Regel : Wenn Sie einen benutzerdefinierten Move-Konstruktor oder den Move-Zuweisungsoperator implementieren, müssen Sie alle 5 davon definieren. Erforderlich für die Move-Semantik.

Destructor, Copy constructor, copy assignment, move constructor, move assignment

Viereinhalb-Prozent-Regel : Wie Rule of 5, aber mit Copy-and-Swap-Idiom. Durch die Einbeziehung der Swap-Methode verschmelzen die Kopierzuweisung und die Verschiebezuweisung zu einem Zuweisungsoperator.

Destructor, Copy constructor, move constructor, assignment, swap (the half part)

Referenzen :

https://www.linkedin.com/learning/c-plus-plus-advanced-topics/rule-of-five?u=67551194 https://en.cppreference.com/w/cpp/language/rule_of_three

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