Conditions pour la génération automatique du cteur par défaut / copie / déplacement et opérateur d'affectation copie / déplacement?

127

Je veux rafraîchir ma mémoire sur les conditions dans lesquelles un compilateur génère généralement automatiquement un constructeur par défaut, un constructeur de copie et un opérateur d'affectation.

Je me souviens qu'il y avait des règles, mais je ne me souviens pas et je ne peux pas non plus trouver une ressource réputée en ligne. Quelqu'un peut-il aider?

oompahloompah
la source

Réponses:

136

Dans ce qui suit, «auto-généré» signifie «implicitement déclaré comme étant par défaut, mais non défini comme supprimé». Il existe des situations dans lesquelles les fonctions membres spéciales sont déclarées, mais définies comme supprimées.

  • Le constructeur par défaut est généré automatiquement s'il n'y a pas de constructeur déclaré par l'utilisateur (§12.1 / 5).
  • Le constructeur de copie est généré automatiquement s'il n'y a pas de constructeur de déplacement déclaré par l'utilisateur ou d'opérateur d'affectation de déplacement (car il n'y a pas de constructeur de déplacement ou d'opérateur d'affectation de déplacement en C ++ 03, cela se simplifie en "toujours" en C ++ 03) ( §12.8 / 8).
  • L'opérateur d'affectation de copie est généré automatiquement s'il n'y a pas de constructeur de déplacement ou d'opérateur d'affectation de déplacement déclaré par l'utilisateur (§12.8 / 19).
  • Le destructeur est généré automatiquement s'il n'y a pas de destructeur déclaré par l'utilisateur (§12.4 / 4).

C ++ 11 et versions ultérieures uniquement:

  • Le constructeur de déplacement est généré automatiquement s'il n'y a pas de constructeur de copie, d'opérateur d'affectation de copie ou de destructeur déclaré par l'utilisateur, et si le constructeur de déplacement généré est valide (§12.8 / 10).
  • L'opérateur d'assignation de déplacement est généré automatiquement s'il n'y a pas de constructeur de copie, d'opérateur d'affectation de copie ou de destructeur déclaré par l'utilisateur, et si l'opérateur d'assignation de déplacement généré est valide (par exemple s'il n'a pas besoin d'attribuer des membres constants) (§12.8 / 21).
Philipp
la source
9
Un destructeur hérité compte-t-il? Je veux dire, disons que j'ai une classe de base avec un destructeur virtuel vide. Empêche-t-il la création de constructeurs de déplacement dans les sous-classes? Si la réponse est oui, cela aidera-t-il si je définis un constructeur de déplacement dans la classe de base?
kamilk
10
Je pense que vous devriez peut-être mentionner que le fait d'avoir des constmembres dans la classe empêchera le constructeur d'être généré automatiquement ...
nonsensickle
Est-ce que "Il existe des situations où les fonctions membres spéciales sont déclarées, mais définies comme supprimées." faire référence à l'endroit où vous avez par exemple const ou des membres de référence où le déplacement sera impossible? Non, cela ne peut pas être, car une copie sera appliquée.
towi le
Je sais qu'il est limité d'envoyer des hyperliens dans ce forum. Mais c'est aussi un bon article - cplusplus.com/articles/y8hv0pDG
bruziuz
Notez qu'à partir de la norme, un constructeur de copie implicitement par défaut " est déconseillé si la classe a un opérateur d'affectation de copie déclaré par l'utilisateur ou un destructeur déclaré par l'utilisateur " ( 12.8 Copie et déplacement d'objets de classe [class.copy] ).
sigy
98

J'ai trouvé le diagramme ci-dessous très utile.

Règles C ++ pour les constructeurs automatiques et les opérateurs d'affectation de Sticky Bits - Devenir une règle de zéro héros

Marco M.
la source
Belle. À quoi se réfère «indépendant»? Indépendant de quoi?
towi le
8
Le cteur / l'affectation de copie sont «indépendants» l'un de l'autre. Si vous n'en écrivez qu'un, le compilateur fournira l'autre. En revanche, si vous fournissez un cteur de déplacement ou une affectation de déplacement, le compilateur ne fournira pas l'autre.
Marco M.
Je me demande quelle est la raison pour laquelle les opérations de copie sont indépendantes. Des raisons historiques peuvent être? ou le fait que la copie ne modifie pas sa cible mais que le déplacement le fait?
RaGa__M
@Explorer_N Oui, rétrocompatibilité, donc des raisons historiques. C'était un mauvais choix de conception il y a longtemps, donc maintenant il y a un besoin de bonnes pratiques comme la "règle de trois" (définir les 3 ou aucun: constructeur de copie, opérateur d'affectation de copie et souvent destructeur) pour éviter les bogues difficiles à trouver.
atablash
@MarcoM., D'après ce que j'ai compris, la condition "Si vous écrivez ..." inclut les deux cas de définition de la fonction membre spéciale sur = delete(évident) ou = default(moins évident pour moi). Ai-je raison?
Enrico Maria De Angelis
2

Projet de norme C ++ 17 N4659

Pour une référence rapide aux standards croisés, jetez un œil aux sections «Implicitement déclarées» des entrées cppreference suivantes:

Les mêmes informations peuvent bien sûr être obtenues auprès de la norme. Par exemple sur le projet standard C ++ 17 N4659 :

15.8.1 "Copier / déplacer les constructeurs" dit pour le constructeur de copie:

6 Si la définition de classe ne déclare pas explicitement un constructeur de copie, un constructeur non explicite est déclaré implicitement. Si la définition de classe déclare un constructeur de déplacement ou un opérateur d'affectation de déplacement, le constructeur de copie déclaré implicitement est défini comme supprimé; sinon, il est défini par défaut (11.4). Ce dernier cas est déconseillé si la classe a un opérateur d'affectation de copie déclaré par l'utilisateur ou un destructeur déclaré par l'utilisateur.

et pour le constructeur de mouvement:

8 Si la définition d'une classe X ne déclare pas explicitement un constructeur de déplacement, un constructeur non explicite sera implicitement déclaré comme étant par défaut si et seulement si

  • (8.1) - X n'a ​​pas de constructeur de copie déclaré par l'utilisateur,

  • (8.2) - X n'a ​​pas d'opérateur d'affectation de copie déclaré par l'utilisateur,

  • (8.3) - X n'a ​​pas d'opérateur d'affectation de déplacement déclaré par l'utilisateur, et

  • (8.4) - X n'a ​​pas de destructeur déclaré par l'utilisateur.

15.8.2 "Opérateur d'affectation de copie / déplacement" dit pour l'affectation de copie:

2 Si la définition de classe ne déclare pas explicitement un opérateur d'affectation de copie, celui-ci est déclaré implicitement. Si la définition de classe déclare un constructeur de déplacement ou un opérateur d'affectation de déplacement, l'opérateur d'affectation de copie déclaré implicitement est défini comme supprimé; sinon, il est défini par défaut (11.4). Ce dernier cas est déconseillé si la classe a un constructeur de copie déclaré par l'utilisateur ou un destructeur déclaré par l'utilisateur.

et pour l'attribution de déménagement:

4 Si la définition d'une classe X ne déclare pas explicitement un opérateur d'assignation de déplacement, l'un sera implicitement déclaré comme étant par défaut si et seulement si

  • (4.1) - X n'a ​​pas de constructeur de copie déclaré par l'utilisateur,
  • (4.2) - X n'a ​​pas de constructeur de déplacement déclaré par l'utilisateur,
  • (4.3) - X n'a ​​pas d'opérateur d'affectation de copie déclaré par l'utilisateur, et
  • (4.4) - X n'a ​​pas de destructeur déclaré par l'utilisateur.

15.4 "Destructeurs" le dit pour les destructeurs:

4 Si une classe n'a pas de destructeur déclaré par l'utilisateur, un destructeur est implicitement déclaré comme étant par défaut (11.4). Un destructeur déclaré implicitement est un membre public en ligne de sa classe.

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