Pravidlo tří (C++)

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 7. dubna 2022; kontroly vyžadují 2 úpravy .

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.

Pravidlo pěti

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; // } };

Kopírovat a sdílet idiom

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();.

Nulové pravidlo

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]

Odkazy

  1. Bjarne Stroustrup . Programovací jazyk C++  (neopr.) . - 3. - Addison-Wesley , 2000. - S. 283-284. - ISBN 978-0201700732 .
  2. Karlsson, Bjorn; Wilson, Matthew. Zákon Velké dvojky . Zdroj C++ . Artima (1. října 2004). Datum přístupu: 22. ledna 2008. Archivováno z originálu 17. března 2012.
  3. Programovací jazyk C++  . - S. 271.
  4. Přesunout operátor přiřazení . En.CPPRreference.com . Datum přístupu: 22. prosince 2014. Archivováno z originálu 23. prosince 2014.
  5. Pravidlo nuly . Hořící nebezpečná zóna . Získáno 29. července 2015. Archivováno z originálu 29. srpna 2015.
  6. Kulikov Alexandr. Pravidlo 3, 5, 0 Habrahabr . Získáno 14. února 2016. Archivováno z originálu 22. února 2016.