Ceci est un suivi de Cette question . Supposons que j'ai ce code: Quelle est une version simplifiée de ce que Cette réponse Suggère. p> Maintenant une fois qu'un destructeur est invoqué à partir de la méthode Est-ce que cela rend le pointeur à l'objet dans l'appel valide à nouveau? P> p> () code> extrémités de vie d'objet et la variable de pointeur
objet code> dans le code d'appel devient invalide. Ensuite, le nouvel objet est créé au même emplacement. P>
6 Réponses :
Strictement, c'est bien. Cependant, sans extrême em> soins, il deviendra un morceau d'UB hideux. Par exemple, toutes les classes dérivées appelant cette méthode n'offriront pas le bon type de re-construit - ou que se passe-t-il si Ce n'est pas strictement ub, mais est un tas de merde géant et échoue et doit être brûlé à la vue. P> classe () code> jette une exception. En outre, cela ne fait rien vraiment. P>
Vos remarques sur le potentiel UB sont précieuses, mais vous ne fournissez aucun argument de sauvegarde de votre affirmation selon laquelle "c'est bien". Pourriez-vous élaborer?
Il existe une citation standard décrivant explicitement la pratique comme légale. Plus précisément, les pointeurs ne sont pas invalides tant qu'il existe un objet du type de droite au bon endroit et de la façon dont il est arrivé qu'il n'y a pas de problème, comme c'était.
Le pointeur connaît seulement son adresse et, dès que vous pouvez confirmer que l'adresse du nouvel objet est celle du pointeur indiquant que la réponse est oui. P>
Il y a des cas où les gens croient que l'adresse ne change pas, mais dans certains cas, cela change, par exemple. Lors de l'utilisation de C RELALELOC () CODE>. Mais c'est une autre histoire. P>
Qu'est-ce que sur la terre realloc code> a à voir avec quelque chose?
Rien, je voulais juste rappeler que parfois les adresses changent. Et c'est la seule raison pour laquelle un pointeur peut devenir invalide, évidemment. Dans ce scénario, pas.
L'objet Ce scénario exact est couvert par la section 3.8.7 de la norme C ++: P>
si, après la fin de la durée de vie d'un objet et avant le stockage
que l'objet occupé est réutilisé ou libéré, un nouvel objet est
créé à l'emplacement de stockage que l'objet d'origine occupé, un
pointeur qui pointa sur l'objet d'origine, une référence qui a fait référence
à l'objet d'origine, ou le nom de l'objet d'origine sera
se réfère automatiquement au nouvel objet et, une fois la durée de vie de la
Un nouvel objet a commencé, peut être utilisé pour manipuler le nouvel objet [...] p>
blockQuote>
Cela dit, cela n'est intéressant que comme code d'apprentissage, en tant que code de production, c'est horrible :) P> code> Le pointeur ne devient pas invalide à tout moment (en supposant que votre destructeur n'appelle pas
supprimer ce code>). Votre objet n'a jamais été traité, il n'a appelé que son destructeur, c'est-à-dire qu'il a nettoyé son état interne (en ce qui concerne la mise en œuvre, veuillez noter que la norme définit strictement que l'objet est détruit après l'appel destructeurs). Comme vous avez utilisé le placement nouveau pour instancier le nouvel objet à la même adresse exactement, il est techniquement correct. p>
Strictement parlant, appeler un destructeur ne "nettoie pas l'état interne", il détruit i> l'objet (selon la terminologie standard (§12.4)). Cependant, votre remarque sur les pointeurs est invalidée uniquement lorsque la mémoire est traitée semble vraie (voir §3.7.4.2). Même s'il n'y a plus d'objet à la mémoire pointée par le pointeur, la mémoire est toujours allouée, le pointeur est toujours valide (au moins, c'est mon interprétation de la norme).
Vous avez raison, mais je décrivais principalement ce qui se passe vraiment sous la cagoule - Je sais pas mal de personnes qui pensent que cette distribution est liée de la méthode destructeurs. J'ai clarifié la réponse.
Création d'un nouvel objet à l'emplacement d'une détruite ne rend aucun pointeur valide à nouveau. Ils peuvent indiquer un nouvel objet valide, mais pas l'objet que vous avez fait référence à l'origine. P>
Vous devez garantir que toutes les références ont été supprimées ou marquées d'une manière ou d'une autre comme invalide avant de détruire l'objet d'origine. P>
Ce serait une situation particulièrement difficile à déboguer. p>
Également incorrect. Un pointeur doit seulement indiquer un objet valide i> du type (du type correct) au moment de la désémarche à être valide. Les pointeurs et les références valides avant méthode code> sont valides après
méthode code>.
@Deadmg: Votre commentaire est incorrect. L'objet peut ne pas être du type correct et qui utilise un pointeur existant imprévisible. Le pointeur peut être déréférencé, mais cela ne le rend pas valide. Si le nouvel objet est d'un type correct, cela rend les choses déroutant et le comportement de programme peu fiable. Un "-1" sur ma réponse est inconnu pour.
Il est complètement appelé pour. S'il reconstruit le type correct, le comportement est bien défini. Le fait qu'il soit difficile de déboguer est certainement vrai - mais c'est pas i> vrai que les pointeurs vers l'ancien objet sont invalides.
Ma réponse est correcte. est i> vrai que les pointeurs sur l'ancien objet sont invalides car il n'y a pas d'objet ancien i>! Bien que le pointeur puisse certainement être déréférencé si i> il pointe vers un objet correctement typé nouveau i>, le résultat d'une opération dépend de ces données ne sera pas correcte et, par conséquent, < I> invalide i>. Vous ne pouvez pas aimer ma réponse, mais respectueusement, veuillez supprimer votre bowvote.
Vous voudrez peut-être reconsidérer explicitement appeler le destructeur. S'il y a du code que vous souhaitez exécuter, cela se trouve dans le destructeur, déplacez ce code à une nouvelle méthode et appelez cette méthode du destructeur pour préserver la fonctionnalité actuelle. Le destructeur est vraiment destiné à être utilisé pour des objets hors de portée. P>
Ceci est explicitement approuvé en 3.8: 7:
3.8 Objet Lifetime [Basic.Life] h3>
7 - Si, après la fin de la vie d'un objet [...], un nouvel objet est créé à l'emplacement de stockage que l'objet d'origine occupé, un pointeur qui pointe vers l'objet d'origine [...] peut être utilisé pour manipuler le nouvel objet, si: (diverses exigences qui sont satisfaites dans ce cas) em> p> blockQuote>
L'exemple donné est le suivant: p>
xxx pré> p>
Éventuellement la plus onéreuse des différentes exigences est que l'objet ne doit pas avoir de membres const code> ou de référence de référence (ni ses membres ne peuvent pas non plus, depuis lors, lorsque vous appliquez ce truc sur un objet que vous appliquez le même tour à tous ses membres et à leurs membres, etc.). Ces membres de données sont probablement la principale raison pour laquelle on pense que quelqu'un penserait: «Je ne peux pas muter l'objet, donc j'ai besoin de le détruire et de le reconstituer», mais ils auraient eu tort.
Donc, tentant de bownvote pour un opérateur d'attribution auto-affectant auto-assignant sans exception ... mais j'ai lu que c'était l'exemple de la norme. -1 à la norme.
N'involterait-il pas complètement les pointeurs vaincre le but du placement nouveau?
Pourquoi cette fonction est-ce virtuelle? C'est un peu effrayant.
De plus, si le constructeur de
classe code> jette à l'exception, vous êtes dans un dilemme éthique. (Et s'il vous plaît i> N'appelez pas votre classe "classe" ...)
@LUC TOURAILLE: Eh bien, je ne suis pas au courant des cas d'esprit où le placement nouveau est appelé à recréer l'objet au même endroit.
Êtes-vous concerné spécifiquement par le fait que le remplacement est effectué à partir d'une méthode de l'objet, d'ailleurs une méthode virtuelle, ou pourrions-nous remplacer votre code d'échantillon par un tel que celui-ci:
struct t {}; T * obj = nouveau t; obj-> ~ t (); nouveau (obj) t; code>?
@LUC TOURAILLE: La principale préoccupation est que le pointeur en question n'a aucune connexion "à l'envers" de l'objet, il devrait donc s'agir d'une fonction membre ou d'une fonction libre ou d'une autre variable de pointeur stockant la même adresse.
@shaparptoots, standard couvre également que :)
une telle utilisation d'un placement explicit et de la destruction d'objets peut être nécessaire pour faire face aux ressources matérielles dédiées et pour écriture des installations de gestion de la mémoire. Code>