La création d'un nouvel objet de classe C avec l'opérateur new () donne une erreur ici:
class C
{
public:
C() {}
virtual ~C() {}
void operator delete(void*) = delete;
};
int main()
{
C* c = new C;
}
avec C2280: 'void C::operator delete(void *)': function was explicitly deleted
Mais quand je remplacerai C() {}
avec C() = default;
ou supprimer la ligne de sorte que le compilateur insère un constructeur par défaut (qui je crois , a le même effet = default
), le code compiler et exécuter.
Quelles sont les différences entre le constructeur par défaut généré par le compilateur et le constructeur par défaut défini par l'utilisateur qui rendent cela possible?
J'ai un indice dans cette publication , mais la classe C ici (sans constructeur fourni par l'utilisateur) n'est pas anodine car le destructeur est virtuel, non?
Compilé avec la dernière version de Visual Studio, c ++ 17.
noexcept
operator delete()
si le constructeur est écrit manuellement ou généré implicitement. Ce qui est conforme à mes attentes - puisqu'une exception peut être levée par l'new
expression, le compilateur doit y accéderoperator delete()
.noexcept
fera compiler le code, mais comment ...?noexcept
comme SebastianRedl l'a mentionné, alors un appel àoperator delete
n'a pas besoin d'être inclus. De plus, g ++ ne se plaint que si le destructeur est virtuel. Sinon, il compile toujours, même si le constructeur lance.Réponses:
new
expression appelle le correspondantoperator new
puis appelle le constructeur. Si le constructeur lève unenew
expression d' exception , il faut annuler l'effet deoperator new
(pour éviter une fuite de mémoire) en appelant le correspondantoperator delete
. Si ce dernier est supprimé, l'new
expression ne peut pas l'appeler, ce qui entraîne le compilateurerror: use of deleted function 'static void C::operator delete(void*)'
.Un
noexcept
constructeur ne peut pas lever une exception, par conséquent, le correspondantoperator delete
n'est pas nécessaire car il ne sera pas appelé par unenew
expression. Undefault
constructeur d'une classe triviale est également unnoexcept
constructeur. La présence d'un destructeur virtuel doitoperator delete
être non supprimée car le destructeur de suppression scalaire spécial (un détail d'implémentation permettant d'activer l'delete
expression via le pointeur de classe de base) invoqueoperator delete
.Il ne semble pas être spécifié par la norme C ++ si le compilateur doit exiger
operator delete
d'être non supprimé même s'il ne peut pas être appelé parnew
expression.gcc
, cependant, il ne semble pas du tout invoquer l' expression correspondanteoperator delete
dansnew
si c'estdelete
d (a posté un rapport de bogue ).la source