Que signifie «par défaut» après une déclaration de fonction d'une classe?

221

J'ai vu defaultutilisé à côté des déclarations de fonction dans une classe. Qu'est ce que ça fait?

class C {
  C(const C&) = default;
  C(C&&) = default;
  C& operator=(const C&) & = default;
  C& operator=(C&&) & = default;
  virtual ~C() { }
};
Paul Manta
la source
26
Que fait le "&" qui précède le "=" dans les déclarations de l'opérateur d'affectation?
dshin
6
@dshin Il s'agit d'une ref-qualification d'une fonction membre .
Kane

Réponses:

249

C'est une nouvelle fonctionnalité C ++ 11 .

Cela signifie que vous souhaitez utiliser la version générée par le compilateur de cette fonction, vous n'avez donc pas besoin de spécifier de corps.

Vous pouvez également utiliser = deletepour spécifier que vous ne voulez pas que le compilateur génère automatiquement cette fonction.

Avec l'introduction des constructeurs de déplacement et des opérateurs d'affectation de déplacement, les règles de génération des versions automatiques des constructeurs, destructeurs et opérateurs d'affectation sont devenues assez complexes. L'utilisation = defaultet = deletefacilite les choses car vous n'avez pas besoin de vous souvenir des règles: vous dites simplement ce que vous voulez arriver.

Peter Alexander
la source
17
= deleteest plus fort: Cela signifie que l'utilisation de cette fonction est interdite, bien qu'elle participe toujours à la résolution de surcharge.
Déduplicateur
2
Mais, si nous voulons utiliser la définition de génération du compilateur, ne devrions-nous pas ignorer l'écriture de cette fonction au lieu de "l'écrire d'abord, puis l'assigner par défaut"?
Mayank Jindal
47

Il s'agit d'une nouvelle fonctionnalité C ++ 0x qui indique au compilateur de créer la version par défaut du constructeur ou de l'opérateur d'affectation respectif, c'est-à-dire celui qui effectue simplement l'action de copie ou de déplacement pour chaque membre. Ceci est utile car le constructeur de déplacement n'est pas toujours généré par défaut (par exemple si vous avez un destructeur personnalisé), contrairement au constructeur de copie (et de même pour l'affectation), mais s'il n'y a rien de non trivial à écrire, il vaut mieux laisser le le compilateur le gère que de l'épeler vous-même à chaque fois.

Notez également qu'un constructeur par défaut ne serait pas généré si vous fournissez un autre constructeur non par défaut. Si vous voulez toujours le constructeur par défaut, vous pouvez également utiliser cette syntaxe pour que le compilateur en crée un.

Comme autre cas d'utilisation, il existe plusieurs situations dans lesquelles un constructeur de copie ne serait pas généré implicitement (par exemple, si vous fournissez un constructeur de déplacement personnalisé). Si vous voulez toujours la version par défaut, vous pouvez la demander avec cette syntaxe.

Voir la section 12.8 de la norme pour plus de détails.

Kerrek SB
la source
5
Bien qu'il soit non seulement pour les constructeurs et les affectations, mais applique également operator new/new[], operator delete/delete[]et leurs surcharges.
Sebastian Mach
21

C'est nouveau en C ++ 11, voir ici . Cela peut être très utile si vous avez défini un constructeur, mais que vous souhaitez utiliser les valeurs par défaut pour les autres. Avant C ++ 11, vous devez définir tous les constructeurs une fois que vous en avez défini un, même s'ils sont équivalents aux valeurs par défaut.

Notez également que dans certaines situations, il est impossible de fournir un constructeur par défaut défini par l'utilisateur qui se comporte de la même manière que le compilateur synthétisé sous l' initialisation par défaut et la valeur . defaultvous permet de récupérer ce comportement.

juanchopanza
la source
5
concernant le deuxième paragraphe, pouvez-vous donner un exemple?
John Smith
11

Un autre cas d'utilisation que je ne vois pas mentionné dans ces réponses est qu'il vous permet facilement de changer la visibilité d'un constructeur. Par exemple, vous souhaitez peut-être qu'une classe amie puisse accéder au constructeur de copie, mais vous ne voulez pas qu'elle soit accessible au public.

dshin
la source
1

Projet standard C ++ 17 N4659

https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 11.4.2 "Fonctions par défaut explicites":

1 Une définition de fonction du formulaire:

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

est appelé une définition par défaut explicite. Une fonction explicitement par défaut doit

  • (1.1) - être une fonction membre spéciale,

  • (1.2) - ont le même type de fonction déclaré (sauf pour les qualificatifs ref éventuellement différents et sauf que dans le cas d'un constructeur de copie ou d'un opérateur d'affectation de copie, le type de paramètre peut être «référence à T non const», où T est le nom de la classe de la fonction membre) comme si elle avait été implicitement déclarée, et

  • (1.3) - pas d'arguments par défaut.

2 Une fonction explicitement par défaut qui n'est pas définie comme supprimée ne peut être déclarée constexpr que si elle aurait été implicitement déclarée comme constexpr. Si une fonction est explicitement par défaut sur sa première déclaration, elle est implicitement considérée comme constexpr si la déclaration implicite le serait.

3 Si une fonction explicitement par défaut est déclarée avec un spécificateur noexcept qui ne produit pas la même spécification d'exception que la déclaration implicite (18.4), alors

  • (3.1) - si la fonction est explicitement par défaut sur sa première déclaration, elle est définie comme supprimée;

  • (3.2) - sinon, le programme est mal formé.

4 [Exemple:

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

- exemple de fin]

5 Les fonctions par défaut explicites et les fonctions déclarées implicitement sont appelées collectivement fonctions par défaut, et la mise en œuvre doit leur fournir des définitions implicites (15.1 15.4, 15.8), ce qui pourrait signifier qu'elles sont supprimées. Une fonction est fournie par l'utilisateur si elle est déclarée par l'utilisateur et non explicitement par défaut ou supprimée lors de sa première déclaration. Une fonction par défaut explicitement fournie par l'utilisateur (c'est-à-dire explicitement par défaut après sa première déclaration) est définie au point où elle est explicitement par défaut; si une telle fonction est implicitement définie comme supprimée, le programme est mal formé. [Remarque: Déclarer une fonction par défaut après sa première déclaration peut fournir une exécution efficace et une définition concise tout en permettant une interface binaire stable à une base de code en évolution. - note de fin]

6 [Exemple:

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

- exemple de fin]

Ensuite, la question est bien sûr de savoir quelles fonctions peuvent être implicitement déclarées et quand cela se produit, ce que j'ai expliqué à:

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source