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.
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; // } };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();.
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]
C++ | |
---|---|
Egenheter | |
Vissa bibliotek | |
Kompilatorer | |
påverkas | |
|