web-dev-qa-db-fra.com

Que signifie "default" après la déclaration de fonction d'une classe?

J'ai vu default utilisé à 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() { }
};
182
Paul Manta

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

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

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

Avec l'introduction des constructeurs de déplacement et des opérateurs d'assignation de déplacement, les règles de génération des versions automatiques des constructeurs, des destructeurs et des opérateurs d'assignation sont devenues assez complexes. Utiliser = default et = delete facilite les choses car vous n'avez pas besoin de vous rappeler les règles: vous dites simplement ce que vous voulez qu'il se passe.

213
Peter Alexander

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 correspondant, c’est-à-dire celle qui effectue simplement la copie ou le déplacement de chaque membre. Ceci est utile car le constructeur de déplacements 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 non-trivial à écrire, il vaut mieux laisser le Le compilateur s'en occupe plutôt que de l'épeler à chaque fois.

Notez également qu'aucun constructeur par défaut ne sera généré si vous fournissez un autre constructeur autre que celui 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.

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.

41
Kerrek SB

C'est nouveau dans C++ 11, voir ici . Cela peut être très utile si vous avez défini un constructeur mais souhaitez utiliser les valeurs par défaut pour les autres. Avant C++ 11, il vous faudrait 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 les initialisations default et value. default vous permet de récupérer ce comportement.

18
juanchopanza

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

10
dshin

C++ 17 Projet de norme N4659

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

1 Une définition de fonction de la forme:

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

est appelée une définition explicitement par défaut. 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ée (à l'exception éventuellement de qualificateurs de référence 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 à Non-const T ”, où T est le nom de la classe de la fonction membre) comme si elle avait été implicitement déclarée, et

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

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

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

  • (3.1) - si la fonction est explicitement définie par défaut sur sa première déclaration, elle est définie comme étant 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

- fin exemple]

5 Les fonctions explicitement définies par défaut et les fonctions déclarées implicitement sont collectivement appelées fonctions définies par défaut et la mise en œuvre doit en fournir des définitions implicites (15.1 15.4, 15.8), ce qui peut signifier définir eux comme supprimés. 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 sur sa première déclaration. Une fonction fournie par défaut par l'utilisateur (c'est-à-dire après la première déclaration ) Est définie au point où elle est explicitement définie par défaut si une telle fonction est implicitement définie comme supprimé, le programme est mal formé. [Remarque: Déclarer une fonction comme étant par défaut après sa première déclaration peut fournit une exécution efficace et une définition concise tout en permettant une interface binaire stable à un code en évolution. base. - 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

- fin exemple]

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