web-dev-qa-db-fra.com

Pourquoi une nouvelle expression [] invoquerait-elle un destructeur?

De la norme C++ 17 (draft ici ), [expr.new]:

Si le new-expression crée un objet ou un tableau d'objets de type classe, le contrôle d'accès et d'ambiguïté est effectué pour la fonction d'allocation, la fonction de désallocation et le constructeur. Si le new-expression crée un tableau d'objets de type classe, le destructeur est potentiellement appelé.

Pourquoi serait new[] invoquer un destructeur? C'est nouveau, après tout. Ce n'est pas supprimer.

39
thb

Si la construction d'un objet dans le tampon lève une exception, les objets précédemment construits doivent être détruits. Cela nécessite un destructeur disponible.

Vous n'avez pas considéré le mot "potentiellement" dans la citation que vous avez mentionnée de la norme.
Cela signifie qu'il est possible que l'invocation du destructeur puisse se produire. Et cela arrivera si la construction d'un objet dans le tableau lève une exception.

Combiné avec la citation suivante de [class.dtor]/12.4 qui mentionne [expr.new], cela devient clair.

Dans chaque cas, le contexte de l'invocation est le contexte de la construction de l'objet. Un destructeur est également invoqué implicitement par l'utilisation d'une expression de suppression pour un objet construit alloué par une nouvelle expression; le contexte de l'invocation est l'expression de suppression. [Remarque: Un tableau de type classe contient plusieurs sous-objets pour chacun desquels le destructeur est appelé. - note de fin ] Un destructeur peut également être invoqué explicitement. Un destructeur est potentiellement appelé s'il est appelé ou comme spécifié dans [expr.new], [class.base.init], et [except.throw]. Un programme est mal formé si un destructeur potentiellement invoqué est supprimé ou inaccessible à partir du contexte de l'invocation.

13
P.W

En action:

#include <iostream>

int counter;

class Destruct
{
public:
    Destruct()
    {
        if (counter++ > 5)
            throw counter;
    }

    ~Destruct()
    {
        std::cout << "Dtor called\n";
    }
};

int main()
{
    try
    {
        new Destruct[10];
    }
    catch (...){}
}

Vous verrez sortir quelque chose comme:

Dtor called
Dtor called
Dtor called
Dtor called
Dtor called
Dtor called
8
Ajay