Comment est “par défaut =” différent de “{}” pour défaut constructeur et le destructeur?
J'ai posté ce que une seule question sur les destructeurs, mais maintenant, je suis en ajoutant l'examen du constructeur par défaut. Voici la question d'origine:
Si je veux donner ma classe un destructeur qui est virtuel, mais est
sinon la même chose que ce que le compilateur de générer, je peux utiliser=default
:class Widget { public: virtual ~Widget() = default; };
Mais il semble que je peux obtenir le même effet avec moins de frappe à l'aide d'un
définition vide:class Widget { public: virtual ~Widget() {} };
Est-il de toute façon dans laquelle de ces deux définitions se comporter différemment?
Sur la base des réponses posté pour cette question, la situation pour le constructeur par défaut semble similaire. Étant donné qu'il n'y a presque pas de différence de sens entre "=default
" et "{}
" pour les destructeurs, est-il de la même façon presque pas de différence de sens entre ces options pour les constructeurs par défaut? C'est, en supposant que je veux créer un type où les objets de ce type seront à la fois créés et détruits, pourquoi aurais-je envie de dire
Widget() = default;
au lieu de
Widget() {}
?
Je m'excuse si l'extension de cette question après son post d'origine est en train de violer certaines règles. L'affichage d'un quasi-identiques question pour les constructeurs par défaut qui m'a frappé aussi l'option moins souhaitable.
- Pas que je sache, mais
= default
est la plus explicite de l'omi, et est compatible avec le support avec des constructeurs. - Je ne sais pas pour vous, mais je pense que l'ancien est conforme à la définition de "trivial destructeur", tandis que les seconds ne le sont pas. Donc
std::has_trivial_destructor<Widget>::value
esttrue
pour la première, maisfalse
pour la deuxième. Quelles sont les implications de ce fait, je ne sais pas non plus. 🙂 - Un destructeur virtuel n'est jamais anodin.
- Je suppose que l'ouverture de mes yeux et en regardant le code serait trop de travail! Merci pour la correction.
Vous devez vous connecter pour publier un commentaire.
C'est une toute autre question quand on parle des constructeurs que des destructeurs.
Si votre destructeur est
virtual
, la différence est négligeable, Howard a souligné. Toutefois, si votre destructeur a été non virtuelle, c'est une histoire complètement différente. La même chose est vraie pour les constructeurs.À l'aide de
= default
syntaxe spéciale de fonctions membres (constructeur par défaut, copier/déplacer des constructeurs ou d'une assignation, destructeurs etc) signifie quelque chose de très différent de simplement faire{}
. Avec ce dernier, la fonction devient "l'utilisateur". Et cela change tout.C'est une simple classe en C++11 définition:
Si vous tentative à défaut de construire un, le compilateur va générer un constructeur par défaut automatiquement. En va de même pour la copie/déplacement et la destruction. Parce que l'utilisateur n'a pas fourni l'une de ces fonctions de membre, le C++11 spécification considère ce dernier comme une "banale" de la classe. Il est donc légal de faire cela, comme memcpy leur contenu autour de les initialiser et ainsi de suite.
Ce:
Comme le nom le suggère, ce n'est plus trivial. Il a un constructeur par défaut qui est fourni par l'utilisateur. Il n'a pas d'importance si elle est vide; en ce qui concerne les règles de C++11, cela ne peut pas être une mince type.
Ce:
De nouveau comme son nom l'indique, c'est un type trivial. Pourquoi? Parce que vous avez dit au compilateur de générer automatiquement le constructeur par défaut. Le constructeur est donc pas "fourni par l'utilisateur." Et par conséquent, le type de compte comme trivial, car elle n'a pas un utilisateur par défaut fourni par le constructeur.
La
= default
syntaxe est principalement là pour faire les choses comme copie de constructeurs ou d'une assignation, lorsque vous ajoutez des fonctions de membre qui empêchent la création de telles fonctions. Mais c'est aussi un déclencheur spécial comportement du compilateur, il est donc utile en défaut constructeurs/destructeurs trop.=default
fonctions) et utilisateur (ce qui est le cas pour{}
) de fonctions. L'utilisateur déclaré et fourni par l'utilisateur, les fonctions peuvent empêcher la génération d'autres membres de la fonction (par exemple, un utilisateur déclaré destructeur empêche la génération des opérations de déplacement), mais seulement à condition de fonction spéciale qui rend une classe non triviale. Droit?= default
semble être utile pour forcer le compilateur à générer un constructeur par défaut en dépit de la présence d'autres constructeurs; le constructeur par défaut n'est pas déclarée implicitement si un autre utilisateur a déclaré constructeurs sont fournis.= default
et{}
à la définition sont possibles et le choix a des effets différents que c'est une ligne de définition.=default
) peut empêcher la génération automatique d'un constructeur de copie, par exemple?Ils sont à la fois non-trivial.
Ils ont tous deux la même noexcept spécification selon la noexcept spécification des bases et des membres.
La seule différence, je suis détecter jusqu'à présent, c'est que si
Widget
contient une base ou d'un membre avec un inaccessibles ou supprimées destructeur:Puis le
=default
la solution sera de compiler, maisWidget
ne sera pas un destructibles type. I. e. si vous essayez de détruire unWidget
, vous obtiendrez une erreur de compilation. Mais si vous ne le faites pas, vous avez un programme de travail.Otoh, que, si vous fournissez les fourni par l'utilisateur destructeur, alors les choses ne compile pas de savoir si ou de ne pas vous détruire un
Widget
:=default;
le compilateur ne génère pas le destructeur sauf s'il est utilisé, et donc de ne pas déclencher une erreur. Cela semble bizarre pour moi, même si pas forcément un bug. Je ne peux pas imaginer ce comportement est mandaté dans la norme.La différence importante entre
et
est que le constructeur par défaut défini avec
B() = default;
est considéré comme non-défini par l'utilisateur. Cela signifie qu'en cas de valeur d'initialisation comme danstype spécial de l'initialisation, qui n'utilise pas un constructeur à tous aura lieu et pour des types intégrés, cela entraînera zéro-initialisation. En cas de
B(){}
cela n'aura pas lieu. La Norme C++ n3337 § 8.5/7 ditPar exemple:
résultat possible:
http://ideone.com/k8mBrd