29 votes

Constructeur de déplacement par défaut vs Constructeur de copie par défaut vs Opérateur d'affectation par défaut

Pourquoi le compilateur C ++ a-t-il plus de restrictions sur les constructeurs de déplacement générés automatiquement que sur le constructeur de copie ou l'opérateur d'affectation généré automatiquement?

Les constructeurs de déplacement générés automatiquement ne sont générés que si l'utilisateur n'a rien défini (par exemple: constructeur, copie, affectation, destructeur ..)

Le constructeur de copie ou l'opérateur d'affectation est généré uniquement si l'utilisateur n'a pas défini respectivement le constructeur de copie ou l'opérateur d'affectation.

Je me demande pourquoi la différence.

13voto

Angew Points 53063

Je crois rétro-compatibilité joue un grand rôle ici. Si l'utilisateur définit une de la "Règle de trois" fonctions (copie ctor, copie d'attribution de l'op, dtor), il peut être assumé que la classe ne comprend certains internes de gestion des ressources. Implicitement la définition d'un constructeur de déplacement peut tout à coup faire la classe non valide lors de la compilation en C++11.

Considérons cet exemple:

class Res
{
  int *data;

public:
  Res() : data(new int) {}

  Res(const Res &arg) : data(new int(*arg.data)) {}

  ~Res() { delete data; }
};

Maintenant, si un défaut constructeur de déplacement a été généré pour cette classe, son invocation conduirait à une double suppression de l' data.

Comme pour l'opérateur d'assignation de déplacement prévention défaut constructeur de déplacement définitions: si l'opérateur d'assignation de déplacement n'est autre chose que par défaut, il serait probablement une erreur d'utiliser la valeur par défaut constructeur de déplacement. C'est juste la "Règle de trois"/"Règle des cinq", en effet.

9voto

Daniel Frey Points 30752

Pour autant que je sais, c'est en raison de la baisse de compatibilité. Considérer les classes écrites en C++ (avant C++11) et qu'arriverait-il si le C++11 pour commencer à générer automatiquement déplacer-ctors en parallèle à l'existant, la copie ctors ou plus généralement tout autre ctor. Il serait facile de briser le code existant, par le passage par le copier-ctor l'auteur de cette catégorie a écrit. Ainsi, les règles pour la génération d'un déplacement-ctor où conçue pour s'appliquer uniquement à la "sécurité" des cas.

Voici l' article de Dave Abrahams sur pourquoi implicite déménagement doit aller, ce qui a finalement conduit les règles actuelles de C++11.

Et c'est un exemple de comment il allait échouer:

// NOTE: This example assumes an implicitly generated move-ctor

class X
{
private:    
    std::vector<int> v;

public:
    // invariant: v.size() == 5
    X() : v(5) {}

    ~X()
    {
        std::cout << v[0] << std::endl;
    }
};

int main()
{
    std::vector<X> y;

    // and here is where it would fail:
    // X() is an rvalue: copied in C++03, moved in C++0x
    // the classes' invariant breaks and the dtor will illegally access v[0].
    y.push_back(X());
}

8voto

Matthieu M. Points 101624

Quand le C++ a été créé, il a été décidé que le constructeur par défaut, constructeur par copie, l'affectation de l'opérateur et le destructeur serait généré automatiquement (à moins que prévu). Pourquoi ? Parce que les compilateurs C++ doit être capable de compiler (la plupart) du code C sémantique identique, et c'est combien de struct de travail en C.

Cependant, plus tard, il fut remarqué que chaque fois qu'un utilisateur écrit une coutume destructeur, elle aura sans doute besoin d'écrire une copie personnalisée-constructeur/l'affectation opérateur de trop; ceci est connu comme la Règle des Trois Grands. Avec le recul, nous pouvons voir qu'il pourrait avoir été spécifié que le constructeur par copie/cession-opérateur/destructeur aurait été générée si aucun des 3 ont été fournis par l'utilisateur, et qu'il aurait aidé à attraper beaucoup de bugs... et encore conserver une compatibilité descendante avec C.

Par conséquent, comme le C++11 est venu autour, il a été décidé que cette fois, ce serait tout à fait à droite: le nouveau coup-constructeur et déplacez-cession-opérateur ne serait généré automatiquement s'il était clair que l'utilisateur n'a pas à faire quelque chose de "spécial" avec la classe. Rien de "spécial" étant défini comme la redéfinition de déplacer/copier/destruction de comportement.

Pour aider avec les cas étaient des gens serait de faire quelque chose de spécial, mais je voulais "généré automatiquement" méthodes spéciales, l' = default de sucre-revêtement a été ajouté ainsi.

Malheureusement, pour des raisons de compatibilité descendante, le comité C++ ne peut pas revenir dans le temps et changer les règles de génération automatique de copie; je souhaite qu'ils avaient déconseillé à ouvrir la voie pour la prochaine version de la Norme, mais je doute qu'ils le feront. il est cependant déconseillé (voir §12.8/7 pour le constructeur de copie par exemple, avec l'aimable autorisation de @Nevin).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X