9
votes

Pourquoi ce destructeur est-il appelé immédiatement après la création?

J'ai la classe suivante: xxx

et un test très simple capable de produire le problème: xxx

Valgrind warns sur une écriture invalide et le débogage a montré pourquoi. CorneyByTestream reçu; appelle le constructeur sans arguments (qui est un peu stupide car il ne peut pas faire rien). reçu = fixebytestream (12); appelle le constructeur avec l'argument entier ... puis appelle immédiatement le destructeur sur lui-même , invalidez l'objet. Cela fonctionne toujours pour une raison quelconque, mais je préfère que ce ne soit pas placé dans une telle situation étrange qui jette des avertissements.

Alors, pourquoi est-il appelé là-bas? Je pourrais quelque peu comprendre si le destructeur était appelé premier , pour se débarrasser de l'objet temporaire inutile (pas qu'il a besoin de), mais j'ai utilisé ce type de correction - désormais-assignez-les pratiquement partout et jamais eu un tel problème auparavant.


3 commentaires

Pas nécessairement votre problème, mais vous devez ajouter un constructeur de copie. Le constructeur de copie actuelle finira par faire duping le pointeur - de sorte que le destructeur appelé d'abord supprimera la mémoire d'un autre objet.


@Tanycorn dans ce cas exacte, il a besoin d'un opérateur d'affectation


à droite - manquait cette partie - c'est juste quelque chose qui s'en tient vraiment


6 Réponses :


1
votes

fixebytestream (12) est attribué à reçu via l'opérateur par défaut =. Notez que vous n'avez pas alloué fixebytestream (12) dans le tas en utilisant nouveau , mais plutôt l'attribuée dans la portée locale sans spécifier de nom pour la variable qui le tiendrait .

Votre code est quelque peu similaire à: xxx

seulement dans mon exemple TEMP a un nom et sa portée est toute la fonction et dans votre code de test TEMP n'a pas de nom, il existe une seule ligne, puis est détruit.

Le fixebytestream (12) Objet Vous "vu créé ne peut pas être utilisé après cette ligne car ce n'est même pas nommé VarAible.


1 commentaires

Vous êtes sûr qu'il utilise un constructeur de copie et non l'opérateur par défaut = ?



-1
votes

Il semble que vous ne comprenez pas le cycle de vie de l'objet et n'interfère pas ce code comme code Java.

Lorsque vous écrivez fixeByTestream reçu; Un objet de type fixeByTestream est créé à l'aide du constructeur sans argument. Et lorsque vous écrivez reçu = fixebytestream (12); Un autre objet est créé, = l'opérateur est appelé et l'objet nouvellement créé est décroissé.

Aussi, vous n'avez pas remplacé l'opérateur = de sorte que l'objet est copié par des octets, ce qui n'est pas correct.


2 commentaires

C'est faux. L'objet précédent n'est pas désttruit, le temporaire est, après sa copie à l'objet précédent.


En outre, ce n'est qu'une coïncidence que dans ce cas opérateur = agit comme une copie bitwise. En vérité, cela invoque l'affectation sur chaque membre.



5
votes

étape par étape: xxx pré>

éditer: p>

Comme je vois qu'il y a beaucoup de réponses erronées fortes> pour cette question, je vais expliquer plus en détail. Je pourrais avoir une certaine haine pour cela, mais c'est un concept assez important et j'ai bownvoché de sorte qu'une mauvaise réponse ne soit pas acceptée et prise de l'acquisition. P>

Vous initialisez essentiellement un objet sur la pile . P>

Je vais simplifier votre cas: P>

{
   A a;
   {
      A b;
      a = b;
   }
}


2 commentaires

Les autres réponses semblent avoir été corrigées.


C'est des informations très utiles, merci pour l'explication détaillée!



0
votes

objet est déjà initialisé sur cette ligne xxx

sur la ligne xxx

vous le réinitialisez-le. La bonne façon de le faire est la suivante: xxx

(je vais certainement aller pour la première)


1 commentaires

Malheureusement, le premier n'est pas possible, car dans la pratique la taille n'est pas connu au moment de la création d'objets (problème de portée). La seconde fonctionnera probablement, mais je dois vraiment configurer le constructeur de copie et l'opérateur d'affectation de toute façon.



11
votes

Il vous manque un opérateur d'affectation. Rappelez-vous le règle de trois (ou cinq).

Le problème est à peu près comme ceci: xxx

Vous ne fournissez aucun opérateur d'affectation, de sorte que la valeur du pointeur dans le temporaire est simplement copiée dans t, puis la mémoire pointée sur est supprimée dans le destructeur .

Aussi: ne pas avoir de constructeur par défaut, si l'objet construit n'est pas valide.


6 commentaires

Honnêtement, je ne m'attendais pas à ce que je devrais remplacer cela pour une copie triviale, merci pour l'information.


@Digitalman Votre code est fondamentalement l'exemple par défaut de la règle de trois. Mais des situations comme celle-ci sont très rares dans le code moderne C ++. Votre exemple d'usuallly serait écrit avec un vecteur et ce serait inutile.


@Digitalman: Vous auriez pu contourner cela de manière triviale en écrivant t t (2); . Qu'est-ce qui vous a donné l'idée de la diviser en deux étapes?


@Kerreksb en quelque sorte je suis content qu'il ait fait. Il a exposé un bug et lui a appris une leçon précieuse.


@Kerrek SB c'était un exemple pour reproduire le problème. Dans mon code actuel, il n'a aucune idée de la taille de la méthode fixeByTesteam doit être jusqu'à quelques niveaux plus profondément dans la portée - et pas avoir une taille changeante est ce qui le rend "fixe".


@Digitalman: Pourquoi ne pas le construire uniquement lorsque vous en avez besoin ou utilisez redimension () à l'heure appropriée?



8
votes

Si votre objet a un constructeur défini par l'utilisateur, il est toujours fort> construit à l'aide d'un constructeur. Il suffit de définir un objet sans aucun argument constructeur utilise le constructeur par défaut indépendant de savoir si l'objet est écrasé par la suite. C'est

FixedByteStream& FixedByteStream::operator= (FixedByteStream& other) {
    this->existing = other.existing;
    this->size     = other.size;
    this->address  = other.address;
    return *this;
}


0 commentaires