Co oznacza „default” po deklaracji funkcji klasy?


Odpowiedzi:


249

Jest to nowa funkcja C ++ 11 .

Oznacza to, że chcesz użyć wygenerowanej przez kompilator wersji tej funkcji, więc nie musisz określać treści.

Możesz także użyć, = deleteaby określić, że nie chcesz, aby kompilator automatycznie generował tę funkcję.

Wraz z wprowadzeniem konstruktorów ruchów i operatorów przypisań ruchów reguły generowania automatycznych wersji konstruktorów, destruktorów i operatorów przypisań stały się dość złożone. Używanie = defaulti = deleteułatwia rzeczy, ponieważ nie musisz pamiętać zasad: po prostu mów, co chcesz zrobić.


17
= deletejest silniejszy: oznacza to, że korzystanie z tej funkcji jest zabronione, chociaż nadal bierze udział w rozwiązywaniu problemów z przeciążeniem.
Deduplicator

2
Ale jeśli chcemy użyć definicji generowania kompilatora, nie powinniśmy pomijać pisania tej funkcji zamiast „najpierw ją piszemy, a potem przypisujemy do domyślnej”?
Mayank Jindal,

47

Jest to nowa funkcja C ++ 0x, która każe kompilatorowi utworzyć domyślną wersję odpowiedniego konstruktora lub operatora przypisania, tj. Taką, która po prostu wykonuje akcję kopiowania lub przenoszenia dla każdego elementu. Jest to przydatne, ponieważ konstruktor ruchu nie zawsze jest generowany domyślnie (np. Jeśli masz niestandardowy destruktor), w przeciwieństwie do konstruktora kopiowania (i podobnie do przypisania), ale jeśli nie ma nic trywialnego do napisania, lepiej pozwolić kompilator poradzi sobie z tym, niż za każdym razem sam.

Zauważ również, że domyślny konstruktor nie zostałby wygenerowany, jeśli podasz inny konstruktor inny niż domyślny. Jeśli nadal chcesz domyślnego konstruktora, możesz użyć tej składni, aby kompilator go stworzył.

Jako kolejny przypadek użycia istnieje kilka sytuacji, w których konstruktor kopiowania nie zostałby wygenerowany niejawnie (np. Jeśli podasz niestandardowy konstruktor przenoszenia). Jeśli nadal chcesz mieć wersję domyślną, możesz zażądać jej za pomocą tej składni.

Szczegółowe informacje można znaleźć w sekcji 12.8 normy.


5
Choć to nie tylko dla konstruktorów i zadań, ale również dotyczy operator new/new[], operator delete/delete[]oraz ich przeciążenia.
Sebastian Mach

21

Jest nowy w C ++ 11, patrz tutaj . Może być całkiem użyteczny, jeśli zdefiniowałeś jednego konstruktora, ale chcesz użyć ustawień domyślnych dla innych. W wersjach wcześniejszych niż C ++ 11 trzeba zdefiniować wszystkie konstruktory po ich zdefiniowaniu, nawet jeśli są one równoważne z ustawieniami domyślnymi.

Należy również pamiętać, że w niektórych sytuacjach niemożliwe jest zapewnienie domyślnego konstruktora zdefiniowanego przez użytkownika, który zachowuje się tak samo jak syntezator kompilatora zarówno w przypadku inicjalizacji domyślnej, jak i wartości . defaultpozwala przywrócić to zachowanie.


5
odnośnie drugiego akapitu, czy możesz podać przykład?
John Smith,

11

Innym przypadkiem użycia, o którym nie widzę wspomnianych w tych odpowiedziach, jest to, że łatwo pozwala ci zmienić widoczność konstruktora. Na przykład może chcesz, aby klasa przyjaciela miała dostęp do konstruktora kopiowania, ale nie chcesz, aby była publicznie dostępna.


1

Wersja standardowa C ++ 17 N4659

https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 11.4.2 „Funkcje domyślnie niewykonane”:

1 Definicja funkcji formularza:

attribute-specifier-seq opt decl-specifier-seq opt declarator virt-specifier-seq opt = default ;

nazywa się definicją jawnie domyślną. Funkcja, która jest wyraźnie domyślnie niewykonana, powinna

  • (1.1) - być specjalną funkcją członka,

  • (1.2) - mają ten sam zadeklarowany typ funkcji (z wyjątkiem możliwie różnych kwalifikatorów ref i z wyjątkiem tego, że w przypadku konstruktora kopii lub operatora przypisania kopii, typ parametru może być „odniesieniem do non-const T”, gdzie T jest nazwa klasy funkcji składowej), jak gdyby została niejawnie zadeklarowana, oraz

  • (1.3) - nie mają domyślnych argumentów.

2 Funkcja jawnie domyślna, która nie jest zdefiniowana jako usunięta, może zostać zadeklarowana jako constexpr, tylko jeśli zostałaby niejawnie zadeklarowana jako constexpr. Jeśli funkcja jest domyślnie domyślnie domyślna w swojej pierwszej deklaracji, jest domyślnie uważana za constexpr, jeśli niejawna deklaracja byłaby.

3 Jeśli funkcja, która jest jawnie domyślna, zostanie zadeklarowana za pomocą specyfikatora noexcept, który nie tworzy tej samej specyfikacji wyjątku, co deklaracja niejawna (18.4), wówczas

  • (3.1) - jeśli funkcja jest domyślnie domyślnie ustawiona w pierwszej deklaracji, jest zdefiniowana jako usunięta;

  • (3.2) - w przeciwnym razie program jest źle sformułowany.

4 [Przykład:

struct S {
  constexpr S() = default;            // ill-formed: implicit S() is not constexpr
  S(int a = 0) = default;             // ill-formed: default argument
  void operator=(const S&) = default; // ill-formed: non-matching return type
  ~ S() noexcept(false) = default;    // deleted: exception specification does not match
private:
  int i;                              // OK: private copy constructor
  S(S&);
};
S::S(S&) = default;                   // OK: defines copy constructor

- koniec przykładu]

5 Funkcje domyślnie niewykonane i funkcje niejawnie zadeklarowane są zbiorczo nazywane funkcjami domyślnymi, a implementacja powinna zapewnić dla nich niejawne definicje (15.1 15.4, 15.8), co może oznaczać zdefiniowanie ich jako usuniętych. Funkcja jest udostępniana przez użytkownika, jeśli jest zadeklarowana przez użytkownika i nie jest wyraźnie domyślnie domyślna ani usunięta przy pierwszej deklaracji. Podana przez użytkownika funkcja domyślnie niewykonana (tj. Wyraźnie domyślnie niewykonana po pierwszej deklaracji) jest zdefiniowana w punkcie, w którym jest wyraźnie domyślnie niewykonana; jeśli taka funkcja jest domyślnie zdefiniowana jako usunięta, program jest źle sformułowany. [Uwaga: Deklaracja funkcji jako domyślnej po pierwszej deklaracji może zapewnić wydajne wykonanie i zwięzłą definicję, jednocześnie umożliwiając stabilny interfejs binarny do ewoluującej bazy kodu. - uwaga końcowa]

6 [Przykład:

struct trivial {
  trivial() = default;
  trivial(const trivial&) = default;
  trivial(trivial&&) = default;
  trivial& operator=(const trivial&) = default;
  trivial& operator=(trivial&&) = default;
  ~ trivial() = default;
};
struct nontrivial1 {
  nontrivial1();
};
nontrivial1::nontrivial1() = default;       // not first declaration

- koniec przykładu]

Następnie pojawia się pytanie, które funkcje można domyślnie zadeklarować i kiedy to nastąpi, co wyjaśniłem na:

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.