Treregel (C++)

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 7 april 2022; kontroller kräver 2 redigeringar .

Regeln om tre (även känd som "Law of the Big Three" eller "Big Three") är en C++- regel som säger att om en klass eller struktur definierar en av följande metoder måste den explicit definiera alla tre metoderna [1 ] :

Dessa tre metoder är speciella medlemsfunktioner som skapas automatiskt av kompilatorn om de inte uttryckligen deklareras av programmeraren. Om en av dem måste definieras av programmeraren, betyder det att den kompilatorgenererade versionen inte tillfredsställer klassens behov i ett fall, och förmodligen inte kommer att göra det i andra fall.

En ändring av denna regel är att om RAII (från engelska.  Resource Acquisition Is Initialization ) används, så kan den använda förstöraren förbli odefinierad (ibland kallad "Law of the Big Two") [2] .

Eftersom implicit definierade konstruktörer och tilldelningsoperatorer helt enkelt kopierar alla datamedlemmar i en klass [3] , är det nödvändigt att definiera explicita kopieringskonstruktörer och kopiatilldelningsoperatorer i fall där en klass kapslar in komplexa datastrukturer eller kan stödja exklusiv åtkomst till resurser. Och även i fall där klassen innehåller konstanta data eller referenser.

Regel av fem

Med lanseringen av den elfte standarden utökades regeln och blev känd som regeln om fem. Nu, när du implementerar konstruktören, måste du implementera:

Regel av fem exempel:

#include <cstring> klass RFive { privat : char * cstring ; offentliga : // Konstruktör med initialiseringslista och kropp RFive ( const char * arg ) : cstring ( new char [ std :: strlen ( arg ) + 1 ]) { std :: strcpy ( cstring , arg ); } // Förstörare ~ RFive () { ta bort [] cstring ; } // Kopiera konstruktör RFive ( const RFive och andra ) { cstring = new char [ std :: strlen ( annan . cstring ) + 1 ]; std :: strcpy ( cstring , annan . cstring ); } // Move constructor, noexcept - för optimering vid användning av standardcontainrar RFive ( RFive && annat ) noexcept { cstring = annat . cstring ; annat . cstring = nullptr ; } // Kopiera uppdragsoperator RFive & operator = ( const RFive & other ) { om ( detta == & andra ) returnera * detta ; char * tmp_cstring = nytt char [ std :: strlen ( annan . cstring ) + 1 ]; std :: strcpy ( tmp_cstring , annan . cstring ); ta bort [] cstring ; cstring = tmp_cstring ; returnera * detta ; } // Flytta uppdragsoperator RFive & operator = ( RFive && other ) noexcept { om ( detta == & andra ) returnera * detta ; ta bort [] cstring ; cstring = annat . cstring ; annat . cstring = nullptr ; returnera * detta ; } // Du kan också ersätta båda uppdragssatserna med följande sats // RFive& operator=(RFive other) // { // std::swap(cstring, annan.cstring); // returnera *detta; // } };

Kopiera och dela idiom

Du bör alltid undvika att duplicera samma kod, för om du ändrar eller fixar ett avsnitt måste du komma ihåg att fixa resten. Kopiera och swap-idiomet låter dig undvika detta genom  att återanvända kopieringskonstruktorkoden, så för RFive-klassen måste du skapa en vänlig swap-funktion och implementera tilldelningsoperatören genom att kopiera och flytta igenom den. Dessutom, med denna implementering, finns det inget behov av att kontrollera självtilldelning.

#include <cstring> klass RFive { // resten av koden RFive & operator = ( const RFive & other ) // Kopiera tilldelningsoperatör { Rfive tmp ( annan ); swap ( * detta , tmp ); returnera * detta ; } RFive & operator = ( RFive && other ) // Flytta tilldelningsoperator { swap ( * detta , annat ); returnera * detta ; } void swap ( RFive & l , RFive & r ) _ { använder std :: swap ; byta ( l . cstring , r . cstring ); } // resten av koden };

Det är också lämpligt för tilldelningsoperatörer att göra returvärdet till en konstant referens: const RFive& operator=(const RFive& other);. Den extra const kommer att hindra oss från att skriva obfuskerad kod så här: (a=b=c).foo();.

Nollregel

Martin Fernandez föreslog också nollregeln. [5] Enligt denna regel bör du inte definiera någon av de fem funktionerna själv; det är nödvändigt att anförtro deras skapande till kompilatorn (för att tilldela dem värdet = default;). För att äga resurser, istället för enkla pekare, bör du använda speciella omslagsklasser, såsom std::unique_ptroch std::shared_ptr. [6]

Länkar

  1. Bjarne Stroustrup . Programmeringsspråket C++  (neopr.) . - 3. - Addison-Wesley , 2000. - S. 283-284. - ISBN 978-0201700732 .
  2. Karlsson, Björn; Wilson, Matthew. Lagen om de två stora . C++-källan . Artima (1 oktober 2004). Tillträdesdatum: 22 januari 2008. Arkiverad från originalet den 17 mars 2012.
  3. Programmeringsspråket C  ++ . - S. 271.
  4. Flytta tilldelningsoperatör . En.CPPReference.com . Datum för åtkomst: 22 december 2014. Arkiverad från originalet 23 december 2014.
  5. Nollregel . Flammande farozon . Hämtad 29 juli 2015. Arkiverad från originalet 29 augusti 2015.
  6. Kulikov Alexander. Regel 3, 5, 0 Habrahabr . Hämtad 14 februari 2016. Arkiverad från originalet 22 februari 2016.