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() { }
};
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() { }
};
Réponses:
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 = delete
pour 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 = default
et = delete
facilite les choses car vous n'avez pas besoin de vous souvenir des règles: vous dites simplement ce que vous voulez arriver.
= delete
est plus fort: Cela signifie que l'utilisation de cette fonction est interdite, bien qu'elle participe toujours à la résolution de surcharge.
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.
operator new/new[]
, operator delete/delete[]
et leurs surcharges.
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 . default
vous permet de récupérer ce comportement.
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.
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é à: