43 votes

Quelle fonction C++ écrit et appelle dans une classe vide ?

Dans le livre C++ efficace j'ai vu le passage ci-dessous :

Par conséquent, si vous écrivez

class Empty{};

c'est essentiellement la même chose que si vous aviez écrit ceci :

class Empty {
public:
    Empty() { ... }
    Empty(const Empty& rhs) { ... }
    ~Empty() { ... }
    Empty& operator=(const Empty& rhs) { ... } // copy assignment operator
};

Le code suivant fera en sorte que chaque fonction soit générée :

Empty e1;
Empty e2(e1);
e2 = e1;

Mais après avoir désassemblé le fichier exécutable qui a été créé en compilant le code ci-dessus, j'ai réalisé que ce n'était pas le cas : il n'y a pas de fonction invoquée.

Voici le principal code d'assemblage :

00000000004006cd <main>:
  4006cd:       55                      push   %rbp
  4006ce:       48 89 e5                mov    %rsp,%rbp
  4006d1:       b8 00 00 00 00          mov    $0x0,%eax
  4006d6:       5d                      pop    %rbp
  4006d7:       c3                      retq 

Il n'y a pas de fonction nommée "Empty" dans l'application .text segment.

Alors quel est en effet le comportement d'un compilateur après que nous ayons appelé un constructeur ou une affectation d'une classe vide ? Génère-t-il des fonctions comme le dit le livre ? Si oui, où sont-elles stockées ?

54voto

mksteve Points 3337

Les fonctions existent, mais peuvent être inlined.

Lorsque le compilateur met les fonctions en ligne, il se rend compte qu'elles ne sont pas opérationnelles et aucun code n'est généré.

Ce que dit le livre est vrai dans une certaine mesure, les fonctions notionnelles sont créées par le compilateur, pour les appels en ligne et directs.

Mais le code généré est vide, donc un compilateur optimisateur supprimera toute trace de la fonction (en mettant en place un pointeur this), et les fonctions ne seront jamais appelées directement.

Le livre ne cherche pas vraiment à expliquer le code généré, mais l'impact de la création d'une classe, et les fonctions "cachées" qu'elle génère pour le fonctionnement normal.

21voto

6502 Points 42700

Ces méthodes sont effectivement générées pour la classe, mais elles sont générées comme "inline".

Étant donné qu'il s'agit d'implémentations membre par membre (par exemple, le constructeur de copie construira par copie tous les membres), lorsque la fonction class est vide, alors rien n'est fait en eux, et étant en ligne, ils sont simplement invisibles.

Il est cependant très important de se rappeler que ces méthodes obtiennent automatiquement une implémentation... par exemple le code

struct Foo {
    char *buf;
    Foo() : buf(new char[10]) {}
    ~Foo() { delete[] buf; }
};

est bogué, car le code généré automatiquement pour le constructeur de copie et l'affectation est erroné et conduit à la suppression multiple du tampon.

Il est bogué non pas à cause de quelque chose qui a été écrit, mais pour quelque chose qui n'a pas été écrit. no a été écrit et c'est délicat. C'est pourquoi il est extrêmement important de se souvenir de ce que le C++ écrira automatiquement pour vous : si cette implémentation correspond à ce que vous voulez, c'est parfait, mais si ce n'est pas le cas, corrigez le problème en fournissant l'implémentation correcte ou interdisez la création ou l'utilisation de ce code erroné.

9voto

Vous et le livre abordez cette situation à partir de différents niveaux d'abstraction.

Le livre utilise le terme "généré" pour faire référence aux fonctions C++ qui sont implicitement définies par le compilateur dans le programme C++ abstrait. Cela se produit absolument.

Vous l'interprétez comme la génération réelle du code machine réel dans le programme traduit. Ce n'est pas ce que cela signifie. La génération du code machine réel est toujours soumise aux caprices du compilateur, tant que la sémantique de votre programme abstrait original est maintenue.

En tant que tel, le livre n'est certainement pas incorrect, même si j'aurais probablement utilisé un autre mot dans un souci de clarté. S'en tenir à la terminologie standard ne fait jamais de mal.

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