Warunki automatycznego generowania domyślnego / kopiuj / przenoszącego narzędzia i operatora przypisania kopiuj / przenieś?

127

Chcę odświeżyć pamięć w warunkach, w których kompilator zazwyczaj automatycznie generuje domyślny konstruktor, konstruktor kopiujący i operator przypisania.

Przypominam sobie, że były pewne zasady, ale nie pamiętam, a także nie mogę znaleźć renomowanego źródła w Internecie. Czy ktoś może pomóc?

oompahloompah
źródło

Odpowiedzi:

136

W dalszej części „wygenerowany automatycznie” oznacza „niejawnie zadeklarowany jako domyślny, ale nie zdefiniowany jako usunięty”. Istnieją sytuacje, w których specjalne funkcje składowe są zadeklarowane, ale zdefiniowane jako usunięte.

  • Domyślny konstruktor jest generowany automatycznie, jeśli nie ma konstruktora zadeklarowanego przez użytkownika (§12.1 / 5).
  • Konstruktor kopiujący jest generowany automatycznie, jeśli nie ma zadeklarowanego przez użytkownika konstruktora przenoszenia ani operatora przypisania przenoszenia (ponieważ nie ma konstruktorów przenoszenia ani operatorów przypisania przenoszenia w C ++ 03, upraszcza to do „zawsze” w C ++ 03) ( § 12.8 / 8).
  • Operator przypisania kopiowania jest generowany automatycznie, jeśli nie ma zadeklarowanego przez użytkownika konstruktora przenoszenia ani operatora przypisania przenoszenia (§12.8 / 19).
  • Destruktor jest generowany automatycznie, jeśli nie ma go zadeklarowanego przez użytkownika (§12.4 / 4).

Tylko C ++ 11 i nowsze:

  • Konstruktor przenoszenia jest generowany automatycznie, jeśli nie ma zadeklarowanego przez użytkownika konstruktora kopiującego, operatora przypisania kopiowania lub destruktora oraz jeśli wygenerowany konstruktor przenoszenia jest prawidłowy (§12.8 / 10).
  • Operator przypisania przeniesienia jest generowany automatycznie, jeśli nie ma zadeklarowanego przez użytkownika konstruktora kopiującego, operatora przypisania kopiowania lub destruktora oraz jeśli wygenerowany operator przypisania przeniesienia jest prawidłowy (np. Gdyby nie musiał przypisywać stałych członków) (§12.8 / 21).
Philipp
źródło
9
Czy dziedziczony destruktor się liczy? To znaczy, powiedzmy, że mam klasę bazową z pustym wirtualnym destruktorem. Czy zapobiega tworzeniu konstruktorów przenoszenia w podklasach? Jeśli odpowiedź brzmi tak, czy pomoże to zdefiniowanie konstruktora przenoszenia w klasie bazowej?
kamilk
10
Myślę, że powinieneś wspomnieć, że być może posiadanie constczłonków w klasie zapobiegnie automatycznemu generowaniu konstruktora ...
nonsensickle
Czy „Istnieją sytuacje, w których specjalne funkcje składowe są zadeklarowane, ale zdefiniowane jako usunięte”. odnieść się do miejsca, w którym masz na przykład stałych lub referencyjnych członków, w przypadku których ruch będzie niemożliwy? Nie, to niemożliwe, ponieważ zostanie zastosowana kopia.
towi
Wiem, że wysyłanie hiperłączy na tym forum jest ograniczone. Ale jest to również dobry artykuł - cplusplus.com/articles/y8hv0pDG
bruziuz
Należy zauważyć, że standardowo konstruktor kopiujący z domyślnymi ustawieniami domyślnymi „ jest przestarzały, jeśli klasa ma operator przypisania kopiowania zadeklarowany przez użytkownika lub destruktor zadeklarowany przez użytkownika ” ( 12.8 Kopiowanie i przenoszenie obiektów klasy [class.copy] ).
Sigy
98

Poniższy diagram uważam za bardzo przydatny.

Reguły C ++ dla konstruktorów automatycznych i operatorów przypisania od Sticky Bits - Stawanie się zasadą Zero Hero

Marco M.
źródło
Piękny. Do czego odnosi się termin „niezależny”? Niezależnie od czego?
towi
8
Osoba kopiująca / przypisanie są „niezależne” od siebie. Jeśli napiszesz tylko jedną, kompilator zapewni drugą. W przeciwieństwie do tego, jeśli podasz albo wskaźnik ruchu, albo przypisanie ruchu, kompilator nie dostarczy drugiego.
Marco M.
Ciekawe, jaki jest powód, dla którego operacje kopiowania są niezależne. Może przyczyny historyczne? lub fakt, że kopia nie zmodyfikuje celu, ale porusza się?
RaGa__M
@Explorer_N Tak, wsteczna kompatybilność, więc historyczne powody. Dawno temu był to zły wybór projektowy, więc teraz istnieje potrzeba dobrych praktyk, takich jak „zasada trzech” (zdefiniuj wszystkie 3 lub brak: konstruktor kopiujący, operator przypisania kopii i często destruktor), aby uniknąć trudnych do znalezienia błędów.
atablash
@MarcoM., O ile zrozumiałem, warunek „Jeśli piszesz ...” obejmuje dwa przypadki ustawienia specjalnej funkcji składowej na = delete(oczywiste) lub = default(dla mnie mniej oczywiste). Czy mam rację?
Enrico Maria De Angelis
2

Wersja robocza standardu C ++ 17 N4659

Aby uzyskać szybkie odniesienie do standardów, zapoznaj się z sekcjami „Zadeklarowane niejawnie” następujących wpisów cppreference:

Te same informacje można oczywiście uzyskać z normy. Np. W wersji roboczej C ++ 17 N4659 :

15.8.1 „Konstruktory kopiowania / przenoszenia” mówią o konstruktorze kopiującym:

6 Jeśli definicja klasy nie deklaruje jawnie konstruktora kopiującego, niejawny jest deklarowany niejawnie. Jeśli definicja klasy deklaruje konstruktor przenoszenia lub operator przypisania przenoszenia, niejawnie zadeklarowany konstruktor kopiujący jest zdefiniowany jako usunięty; w przeciwnym razie jest definiowany jako default (11.4). Drugi przypadek jest przestarzały, jeśli klasa ma zadeklarowany przez użytkownika operator przypisania kopiowania lub destruktor zadeklarowany przez użytkownika.

a dla konstruktora przenoszenia:

8 Jeśli definicja klasy X nie deklaruje jawnie konstruktora przenoszenia, niejawny konstruktor zostanie niejawnie zadeklarowany jako domyślny wtedy i tylko wtedy, gdy

  • (8.1) - X nie ma zadeklarowanego przez użytkownika konstruktora kopiującego,

  • (8.2) - X nie ma zadeklarowanego przez użytkownika operatora przypisania kopii,

  • (8.3) - X nie ma operatora przypisania przeniesienia zadeklarowanego przez użytkownika, a

  • (8.4) - X nie ma destruktora zadeklarowanego przez użytkownika.

15.8.2 „Operator kopiuj / przenieś przypisanie” mówi o przypisaniu kopii:

2 Jeśli definicja klasy nie deklaruje jawnie operatora przypisania kopiowania, jest on deklarowany niejawnie. Jeśli definicja klasy deklaruje konstruktor przenoszenia lub operator przypisania przenoszenia, niejawnie zadeklarowany operator przypisania kopiowania jest zdefiniowany jako usunięty; w przeciwnym razie jest definiowany jako default (11.4). Ten ostatni przypadek jest przestarzały, jeśli klasa ma zadeklarowany przez użytkownika konstruktor kopiujący lub destruktor zadeklarowany przez użytkownika.

a do przeniesienia:

4 Jeśli definicja klasy X nie deklaruje jawnie operatora przypisania przeniesienia, zostanie on niejawnie zadeklarowany jako domyślny wtedy i tylko wtedy, gdy

  • (4.1) - X nie ma zadeklarowanego przez użytkownika konstruktora kopiującego,
  • (4.2) - X nie ma zadeklarowanego przez użytkownika konstruktora przenoszenia,
  • (4.3) - X nie ma operatora przypisania kopii zadeklarowanego przez użytkownika, a
  • (4.4) - X nie ma destruktora zadeklarowanego przez użytkownika.

15.4 „Destructors” mówi o destruktorach:

4 Jeśli klasa nie ma destruktora zadeklarowanego przez użytkownika, destruktor jest niejawnie deklarowany jako domyślny (11.4). Niejawnie zadeklarowany destruktor jest wbudowanym publicznym składnikiem swojej klasy.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
źródło