Що означає "за замовчуванням" після оголошення функції класу?


221

Я бачив defaultвикористані поруч із функціями декларацій у класі. Що це робить?

class C {
  C(const C&) = default;
  C(C&&) = default;
  C& operator=(const C&) & = default;
  C& operator=(C&&) & = default;
  virtual ~C() { }
};

26
Що робить "&", що передує "=" в деклараціях оператора призначення?
dshin

Відповіді:


249

Це нова функція C ++ 11 .

Це означає, що ви хочете використовувати створену компілятором версію цієї функції, тому вам не потрібно вказувати тіло.

Ви також = deleteможете вказати, що ви не хочете, щоб компілятор автоматично генерував цю функцію.

З впровадженням конструкторів переміщення та операторів присвоєння переміщення правила щодо створення автоматичних версій конструкторів, деструкторів та операторів присвоєння стали досить складними. Використання = defaultта = deleteполегшує справи, оскільки вам не потрібно пам’ятати правила: ви просто говорите, що хочете, щоб сталося.


17
= deleteсильніше: Це означає, що використовувати цю функцію заборонено, хоча вона все ще бере участь у вирішенні перевантаження.
Дедупликатор

2
Але, якщо ми хочемо використовувати визначення генератора компілятора, то чи не слід ми пропускати написання цієї функції замість того, щоб "спочатку записати її, а потім призначити її за замовчуванням"?
Mayank Jindal

47

Це нова функція C ++ 0x, яка повідомляє компілятору створити версію за замовчуванням відповідного конструктора або оператора присвоєння, тобто ту, яка щойно виконує дію копіювання або переміщення для кожного члена. Це корисно, оскільки конструктор переміщення не завжди генерується за замовчуванням (наприклад, якщо у вас є спеціальний деструктор), на відміну від конструктора копіювання (і аналогічно для призначення), але якщо немає нічого нетривіального для запису, краще дозволити компілятор впорається з цим, ніж щоразу промальовувати.

Також зауважте, що конструктор за замовчуванням не створюється, якщо ви надаєте будь-який інший конструктор, який не використовується за замовчуванням. Якщо ви все ще хочете конструктора за замовчуванням, ви також можете використовувати цей синтаксис, щоб компілятор зробив його.

Як інший випадок використання, існує кілька ситуацій, коли конструктор копій не створюється неявно (наприклад, якщо ви надаєте користувацький конструктор переміщення). Якщо ви все ще хочете версії за замовчуванням, ви можете надіслати запит на неї за допомогою цього синтаксису.

Детальніше див. Розділ 12.8 стандарту.


5
Хоча це не тільки для конструкторів і завдань, але також відноситься і до operator new/new[], operator delete/delete[]і їх перевантаження.
Себастьян Мах

21

Він новий у C ++ 11, дивіться тут . Це може бути дуже корисно, якщо ви визначили один конструктор, але хочете використовувати параметри за замовчуванням для інших. Pre-C ++ 11 вам потрібно буде визначити всі конструктори, як тільки ви їх визначили, навіть якщо вони еквівалентні за замовчуванням.

Також зауважте, що в певних ситуаціях неможливо надати визначений користувачем конструктор за замовчуванням, який поводиться так само, як синтезований компілятором, і за ініціалізацією за замовчуванням, і за значенням . defaultдозволяє повернути таку поведінку.


5
щодо другого абзацу, чи можете ви навести приклад?
Джон Сміт

11

Інший випадок використання, який я не бачу в цих відповідях, - це те, що він дозволяє легко змінити видимість конструктора. Наприклад, можливо, ви хочете, щоб клас друзів мав доступ до конструктора копій, але ви не хочете, щоб він був загальнодоступним.


1

C ++ 17 стандартна тяга N4659

https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 11.4.2 "Явні дефолтні функції":

1 Визначення функції форми:

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

називається явно дефолтним визначенням. Функція, яка є явно дефолтом, повинна

  • (1.1) - бути функцією спеціального члена,

  • (1.2) - мають той самий оголошений тип функції (за винятком можливо різних класифікаторів, за винятком випадків, що стосується конструктора копії або оператора присвоєння копії, тип параметра може бути "посиланням на нестандартний T", де T є назва класу функції-члена), як ніби це було неявно оголошено, і

  • (1.3) - не мають аргументів за замовчуванням.

2 Явно дефолтована функція, яка не визначена як видалена, може бути оголошена constexpr, тільки якщо вона була б неявно оголошена як constexpr. Якщо функція явно за замовчуванням у своєму першому оголошенні, вона неявно вважається constexpr, якщо неявна заява буде.

3 Якщо функція, яка явно встановлена ​​за замовчуванням, оголошена за допомогою специфікатора noexcept, який не створює таку ж специфікацію винятків, що і неявна декларація (18.4), тоді

  • (3.1) - якщо функція явно за замовчуванням у своєму першому оголошенні, вона визначається як видалена;

  • (3.2) - інакше програма неправильно сформована.

4 [Приклад:

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

- кінцевий приклад]

5 Явно дефолтовані функції та неявно оголошені функції називаються спільно визначеними функціями, і реалізація повинна містити неявні визначення для них (15.1 15.4, 15.8), що може означати визначення їх як видалених. Функція надається користувачем, якщо вона оголошена користувачем і не є явним за замовчуванням або видалена в першій декларації. Надана користувачем функція явного дефолту (тобто явно дефолт після його першого оголошення) визначається в точці, де вона явно дефолт; якщо така функція неявно визначена як видалена, програма неправильно формується. [Примітка: Оголошення функції за замовчуванням після її першого оголошення може забезпечити ефективне виконання та стисле визначення, одночасно дозволяючи стабільному бінарному інтерфейсу до кодової бази, що розвивається. - кінцева примітка]

6 [Приклад:

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

- кінцевий приклад]

Тоді, звичайно, питання, які функції можна неявно оголосити, і коли це відбувається, що я пояснив у:

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.