Pourquoi ne puis-je pas appeler le constructeur de ma classe à partir d'une instance de cette classe en C ++?

StackOverflow https://stackoverflow.com/questions/2146901

  •  23-09-2019
  •  | 
  •  

Question

Quand peut-on un objet d'une classe appeler la destructor de cette classe, comme si elle est une fonction régulière? Pourquoi ne peut-il appeler le constructeur de la même classe, comme l'une de ses fonctions régulières? Pourquoi le compilateur nous empêche de le faire?

Par exemple:

class c
{
public:
   void add() ;
   c();
   ~c() ;
};

void main()
{
 c objC  ;
 objC.add() ;
 objC.~c() ; // this line compiles
 objC.c() ;  // compilation error
}
Était-ce utile?

La solution

Par définition, un constructeur est appelée une seule fois, lorsque l'objet est créé. Si vous avez accès à un objet, il doit avoir été créé, de sorte que vous n'êtes pas autorisé à appeler le constructeur à nouveau - c'est la raison pour laquelle le constructeur appelle explicites ne sont pas autorisés. De même, ne doivent Destructeurs être appelé une fois, lorsque l'objet est détruit. Si cela pouvait toujours fait automatiquement, la langue serait également interdire les appels explicites destructor.

Cependant, dans certains cas, vous voudrez peut-être un contrôle précis sur la gestion de la mémoire et la capacité de créer et de détruire explicitement les objets dans la mémoire que vous gérez. A cet effet, la langue offre « placement nouvelle » pour créer un objet à un emplacement arbitraire et destructor explicite appelle à détruire les objets créés de cette façon. Un appel explicite constructeur ne serait pas utile, puisque vous devez être en mesure de préciser l'emplacement du nouvel objet - de sorte que vous obtenez « placement nouvelle » place. Un appel explicite destructor est suffisante, il n'y a donc pas besoin d'inventer une sorte de correspondance « placement supprimer ».

: il n'y a pas d'utilisation valable pour les appels explicites constructeur, donc ils ne sont pas autorisés. Il y a une utilisation valable pour les appels destructor explicites, ils sont (syntaxiquement) a permis, avec la règle que vous ne devez jamais les utiliser sur des objets qui ne seront pas autrement détruits, soit des objets créés à l'aide de « placement nouvelle », et que de cas les appeler exactement une fois. comme tant d'erreurs C ++, de les utiliser d'une autre façon, mais compilera donner un comportement non défini.

Autres conseils

Je pense que vous pouvez appeler explicitement le destructeur si vous assurez-vous que l'instance est remplacé / recréée par un appel à un placement nouveau:

class c
{
public:
   void add() ;
   c();
   ~c() ;
};

int main()
{
 c objC  ;
 objC.add() ;
 objC.~c() ; // this line compiles
 new (&objC) c;  // placement new invokes constructor for the given memory region
}

Je ne l'ai jamais vu cela dans la pratique, mais logiquement il devrait fonctionner (à moins que le constructeur de c peut lancer, dans ce cas, je pense, l'enfer pourrait se détacher pendant le déroulement pile).

Cependant, ce que vous voulez sans doute est juste affectation:

objC = c();

Si le destructor a des effets secondaires que vous êtes intéressé, mettre en œuvre la cession en utilisant l'idiome copier-échange qui obtient le destructor invoqué pour la valeur « à la main gauche ».

A destructor doit être appelée sur une instance existante d'une classe - destructing l'instance est ce qu'il fait. Un constructeur crée une toute nouvelle instance d'une classe, donc appel à une instance existante n'a pas de sens.

Ceci est similaire à la façon nouvelle et supprimer le travail:

int * p = new int;    // call to new needs no existing instance
delete p;             // call to delete requires existing instance

Et notez dans votre code, l'objet serait détruit deux fois, une fois explicitement, et une fois implicitement à la fin de sa portée englobante. En général, vous n'appelez explicitement destructor si vous faites quelque chose d'inhabituel, impliquant probablement l'utilisation d'un placement nouveau.

Si vous avez vraiment besoin de faire quelque chose comme cela, il suffit de créer une fonction supplémentaire et appeler de l'extérieur et du constructeur lui-même, mais nous allons voir ce qui se passe quand vous avez besoin d'un tel appel:

#include<new>

class A
{
//members
};

int main()
{
//allocate buffer
char* buffer = new char[sizeof(A)];
//construct A on that memory space
A * ptrToA = ::new (buffer) A();
//destroy the object
ptrToA->~A();
//deallocate the buffer
delete[] buffer;
}

Un exemple où vous pouvez trouver le placement nouvel usage est la norme conteneurs. L'allocateur prend la responsabilité d'affecter le tampon (allouer élément) et les objets sont réalisés au cours de cette tampon comme ils sont ajoutés dans le récipient. Par exemple, lorsque vous faites réserve sur l'objet vectoriel, il se réserve l'espace pour les objets N signifiant alloue de l'espace pour les objets N, mais ne les construisent pas. Puis quand vous ne push_back etc, d'ajouter des éléments, ils sont créés au cours de cette tampon. Au fond, il est une technique pour réduire les frais généraux de des appels répétés à la fonction d'allocation de mémoire. Et puis lorsque vous avez terminé, le vecteur destructor détruirait les objets appelant la destructor explicitement tous les objets, puis appeler le deallocate () fonction de l'allocateur pour libérer la mémoire. Espérons que cela aide.

Essayez ceci:

obj.ClassName :: ClassName (); // cela fonctionne dans le compilateur VC 6.0

Une autre façon de penser à la restriction est qu'un constructeur est pas juste une autre fonction. Considérez sa définition: contrairement à d'autres fonctions, il n'a pas de valeur de retour, et il peut avoir une liste d'initialisation. Qu'il arrive juste d'avoir la plupart de la syntaxe d'une fonction est une sorte de coïncidence; il existe vraiment que dans le but d'initialiser une nouvelle instance d'un objet.

Le constructeur est là "c ()" utilisé avec le nouveau, à savoir

c objC = new c();

Si vous voulez appeler votre constructeur en dehors de la construction proprement dite de l'instance de la classe alors soit vous ne l'avez pas compris le but du constructeur ou essayez de mettre la fonctionnalité là-dedans qui ne devrait pas être là.

Vous demandez au sujet d'un style particulier de la syntaxe plus d'une limitation de la langue. C ++ vous permet d'appeler le constructeur ou destructor d'un objet.

c objC;
objC.~c();  // force objC's destructor to run
new(&objC); // force objC's constructor to run

Pourquoi les concepteurs de langage pas utiliser la syntaxe suivante?

c objC;
delete(&objC) c; // force objC's destructor to run
new(&objC) c;    // force objC's constructor to run

Ou pourquoi pas:

c objC
objC.~c(); // force objC's destructor to run
objC.c();  // force objC's constructor to run

Mon opinion quant à la raison pour laquelle ils ont choisi la syntaxe qu'ils ont fait: La première variante est plus flexible que la seconde. Je peux appeler le constructeur / destructor sur une adresse non seulement une instance. Cette flexibilité est nécessaire pour l'allocation, mais non pour la destruction. Aussi la première suppression de l'option semble être très dangereux une fois virtuel se Destructeurs pour le désordre.

vous pouvez appeler le constructeur de classe en utilisant la typeof d'une instance:

class c
{
public:
   void add() ;
   c();
   ~c() ;
};

void main()
{
 c objC  ;
 objC.add() ;
 objC.~c() ; // this line compiles (but is a bad idea)
 typeof objC otherObjC;  // so does this.
}

Cela n'affecte pas la valeur de la objC instance, mais crée une nouvelle instance otherObjC utilisant le constructeur de la classe de objC.

Note:. Cela peut faire quelque chose que vous ne vous attendez pas si le type statique est un baseclass du type dynamique de l'instance que vous avez

Qui a dit que vous ne pouvez pas? Il suffit de savoir comment.

void Foo::Bar() {
  *this = Foo(); // Reset *this
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top