Pravidlo tří (také známé jako „Zákon velké trojky“ nebo „Velká trojka“) je pravidlo C++ , které říká, že pokud třída nebo struktura definuje jednu z následujících metod, musí explicitně definovat všechny tři metody [1 ] :
Tyto tři metody jsou speciální členské funkce , které jsou automaticky vytvořeny kompilátorem, pokud nejsou explicitně deklarovány programátorem. Pokud jeden z nich musí být definován programátorem, pak to znamená, že verze vygenerovaná kompilátorem v jednom případě neuspokojuje potřeby třídy a v jiných pravděpodobně neuspokojí.
Dodatek k tomuto pravidlu je, že pokud se použije RAII (z angl. Resource Acquisition Is Initialization ), pak použitý destruktor může zůstat nedefinovaný (někdy označovaný jako „Zákon velké dvojky“) [2] .
Protože implicitně definované konstruktory a operátory přiřazení jednoduše zkopírují všechny datové členy třídy [3] , je definování konstruktorů explicitní kopie a operátorů přiřazení kopie nezbytné v případech, kdy třída zapouzdřuje složité datové struktury nebo může podporovat výhradní přístup ke zdrojům. A také v případech, kdy třída obsahuje konstantní data nebo odkazy.
S vydáním jedenáctého standardu se pravidlo rozšířilo a stalo se známým jako pravidlo pěti. Nyní, když implementujete konstruktor, musíte implementovat:
Pravidlo pěti příkladů:
#include <cstring> třída RFive { soukromé : char * cstring ; veřejnost : // Konstruktor s inicializačním seznamem a tělem RFive ( const char * arg ) : cstring ( nový znak [ std :: strlen ( arg ) + 1 ]) { std :: strcpy ( cstring , arg ); } // Destruktor ~ RFive () { delete [] cstring ; } // Kopírovat konstruktor RFive ( const RFive a další ) { cstring = new char [ std :: strlen ( other . cstring ) + 1 ]; std :: strcpy ( cstring , other . cstring ); } // Přesunout konstruktor, noexcept - pro optimalizaci při použití standardních kontejnerů RFive ( RFive && other ) noexcept { cstring = jiný . cstring ; jiný . cstring = nullptr ; } // Kopírování operátoru přiřazení RFive & operátor = ( const RFive a další ) { if ( toto == a další ) vrátit * toto ; char * tmp_cstring = nový char [ std :: strlen ( other . cstring ) + 1 ]; std :: strcpy ( tmp_cstring , other . cstring ); delete [] cstring ; cstring = tmp_cstring ; vrátit * toto ; } // Přesunutí operátoru přiřazení RFive & operator = ( RFive && other ) noexcept { if ( toto == a další ) vrátit * toto ; delete [] cstring ; cstring = jiný . cstring ; jiný . cstring = nullptr ; vrátit * toto ; } // Oba příkazy přiřazení můžete také nahradit následujícím příkazem // RFive& operator=(RFive other) // { // std::swap(cstring, other.cstring); // return *toto; // } };Vždy byste se měli vyvarovat duplikování stejného kódu, protože pokud změníte nebo opravíte jednu sekci, budete muset pamatovat na opravu zbytku. Idioma copy and swap vám umožňuje se tomu vyhnout opětovným použitím kódu konstruktoru kopírování, takže pro třídu RFive budete muset vytvořit přátelskou funkci swap a implementovat operátor přiřazení tím, že ji zkopírujete a projdete. Navíc s touto implementací není potřeba kontrolovat samopřiřazení.
#include <cstring> třída RFive { // zbytek kódu RFive & operator = ( const RFive & other ) // Kopírovat operátor přiřazení { Rfive tmp ( jiné ); swap ( * this , tmp ); vrátit * toto ; } RFive & operator = ( RFive && other ) // Přesunutí operátoru přiřazení { swap ( * toto , jiné ); vrátit * toto ; } výměna za zrušení přátel ( RFive & l , RFive & r ) { pomocí std :: swap ; swap ( l . cstring , r . cstring ); } // zbytek kódu };Pro operátory přiřazení je také vhodné, aby návratová hodnota byla konstantní odkaz: const RFive& operator=(const RFive& other);. Extra const nám zabrání psát zmatený kód, jako je tento: (a=b=c).foo();.
Martin Fernandez také navrhl nulové pravidlo. [5] Podle tohoto pravidla byste neměli sami definovat žádnou z pěti funkcí; je nutné svěřit jejich vytvoření překladači (přiřadit jim hodnotu = default;). Chcete-li vlastnit zdroje, místo jednoduchých ukazatelů byste měli používat speciální třídy obalů, jako jsou std::unique_ptra std::shared_ptr. [6]
C++ | |
---|---|
Zvláštnosti | |
Některé knihovny | |
Kompilátory | |
ovlivnil | |
|