Appel destructeur et puis constructeur (réinitialisation d'un objet)
Je veux réinitialiser un objet. Puis-je le faire de la manière suivante?
anObject->~AnObject();
anObject = new(anObject) AnObject();
//edit: this is not allowed: anObject->AnObject();
Ce code est évidemment un sous-ensemble du cycle de vie typique d'un objet alloué par le placement de nouvelles:
AnObject* anObject = malloc(sizeof(AnObject));
anObject = new (anObject) AnObject(); //My step 2.
//...
anObject->~AnObject(); //My step 1.
free(anObject)
//EDIT: The fact I used malloc instead of new doesn't carry any meaning
La seule chose qui a changé, c'est l'ordre de constructeur et le destructeur des appels.
Alors, pourquoi dans le FAQ suivante
les menaces apparaissent?
[11.9] Mais ce que je peux appeler explicitement une
destructeur si j'ai alloué mon objet
avec de nouvelles?FAQ: Vous ne pouvez pas, sauf si l'objet a été
alloués avec la mise en place de nouvelles. Les objets
créé par le nouveau doit être supprimée, ce qui
fait deux choses (rappelez-vous): appels
le destructeur, puis libère la mémoire.FQA: Traduction: supprimer est un moyen de
explicitement appel d'un destructeur, mais il
aussi désalloue la mémoire. Vous pouvez
aussi appeler un destructeur sans
la désallocation de la mémoire. C'est moche et
inutile dans la plupart des cas, mais vous pouvez le faire
qu'.
Le destructeur/appel du constructeur est évidemment normal de code C++. Garanties utilisées dans le code directement le résultat de la dans le placement de nouvelles garanties. Il est la base de la norme, c'est solide comme le roc chose. Comment peut-il être appelé "sale" et être présenté comme quelque chose de fiable?
Pensez-vous que c'est possible, que le placement et le non-placement de la mise en œuvre de nouvelles sont-elles différentes? Je suis en train de réfléchir certains malades possibilité, que le nouveau peut par exemple mettre la taille du bloc de mémoire alloué avant le bloc, ce qui fait que le placement de nouveaux évidemment ne serait pas le faire (parce qu'il n'a pas d'allouer de la mémoire). Cela pourrait entraîner un écart pour quelques problèmes... Est nouveau() de la mise en œuvre possible?
Je veux vérifier que je n'ai pas manqué de rien comme la dernière modification en question.
OriginalL'auteur | 2009-07-14
Vous devez vous connecter pour publier un commentaire.
Ne pas se faire sucer par la FQA troll. Comme d'habitude, il obtient le des faits erronés.
Vous pouvez certainement appeler le destructeur directement, pour tous les objets qu'ils sont créés avec la mise en place de nouvelles ou pas. Moche est dans l'œil de celui qui regarde, il est en effet rarement nécessaire, mais le fait est que les deux allocation de mémoire et de création de l'objet doit être équilibré.
"Régulier" de new/delete simplifie un peu de lier l'allocation de mémoire et de création de l'objet ensemble, et l'allocation de pile simplifie encore plus loin en faisant à la fois pour vous.
Cependant, la suite est parfaitement légal:
Les deux objets sont détruits, et la pile de la mémoire est automatiquement recyclé trop. pourtant, contrairement à la FQA revendications, le premier appel du destructeur n'est pas précédée par le placement de nouveaux.
Pensez-vous que c'est possible, que le placement et le non-placement de la mise en œuvre de la nouvelle peut-elle différente? Je suis en train de réfléchir certains malades possibilité, que régulièrement de nouveaux pouvez par exemple mettre la taille du bloc de mémoire alloué avant le bloc, et le placement de nouveaux évidemment pas (car il n'a pas allouer de la mémoire). Cela pourrait entraîner un écart pour quelques problèmes...
Il n'a pas d'importance comment ils diffèrent. La mise en œuvre doit s'assurer de mon code ci-dessus fonctionne, parce que c'est conforme. Poussière de lutin qui est permis.
Pourquoi
(&bar)->~CBar();
au lieu debar.~CBar();
?À la fois juridiques et de faire la même chose, mais la question à l'origine utilisé
->~
donc je n'ai pas le changer.OriginalL'auteur MSalters
Pourquoi ne pas mettre en œuvre une méthode Clear (), qui fait tout ce que le code dans le corps du destructeur? Le destructeur alors juste des appels Clear() et que vous appelez Clear() directement sur un objet pour "réinitialiser".
Une autre option, en supposant que votre classe permet l'affectation correctement:
- Je utiliser ce modèle pour la réinitialisation de std::stack instances, comme la pile adaptateur n'
ne pas fournir une fonction claire.
Vous devez maintenir le destructeur "correct" - je suggère de déplacer le destructeur de code dans la méthode Clear (), afin que le destructeur ne contient qu'un seul appel à Clear(). J'écris presque tous mes propre code de cette façon, BTW.
N'est-il pas impossible à mettre en œuvre "destructeur" méthode Clear ()? Il aurait à n'importe quel segment de mémoire allouée membres lorsqu'il est appelé à partir de destructeur. Mais lorsqu'un reset comme méthode, il aurait pour seul de ces membres et de les laisser utilisable. Cela nécessiterait de mettre en œuvre la méthode Init() et de l'appeler à partir d'un constructeur. Réinitialisation de la méthode d'appel Clear() et puis Init(). Init méthodes ressemblent à des non-RAII code. Et que lorsque plusieurs constructeurs sont nécessaires? Cela peut compliquer les choses.
Il dépend de la classe sémantique. Si la reconstruction de la classe après clair, c'est cher, puis utiliser ma deuxième suggestion. Je dirais que l'un des deux est susceptible d'être moins compliqué que de vous embêter avec un destructeur explicite des appels et l'utilisation du placement de nouvelles.
OriginalL'auteur
Techniquement, c'est une mauvaise pratique de l'appel des constructeurs ou destructeurs explicitement.
Le mot clé delete finit par les appeler lorsque vous l'utilisez. En va de même pour les nouveaux avec des constructeurs.
Je suis désolé, mais ce code me donne envie de m'arracher les cheveux. Vous devriez faire comme ceci:
Allouer une nouvelle instance d'un objet
Supprimer une instance d'un objet
Ne JAMAIS faire cela:
Si vous devez "reset" un objet, soit de créer une méthode qui efface toutes les variables d'instance à l'intérieur, ou de ce que je voudrais vous recommandons de le faire est de Supprimer l'objet et de répartir vous-même un nouveau.
Qui ne signifie rien. Perl a environ six façons d'écrire une boucle for. Juste parce que vous POUVEZ faire des choses dans une langue parce qu'ils sont pris en charge ne signifie pas que vous devriez utiliser. Diable, je pourrais écrire tout mon code à l'aide de pour basculer états parce que le "Cœur" de la langue prend en charge. N'est pas une bonne idée.
Pourquoi êtes-vous à l'aide de malloc lorsque de toute évidence, vous n'avez pas à. Malloc est un C méthode.
New et Delete sont vos amis en C++
"Réinitialisation" un Objet
Là vous allez. De cette façon, vous permet d'économiser de inutilement l'allocation et la désallocation de la mémoire dans une dangereuse de la mode. Écrivez votre méthode Reset() pour effacer la valeur de tous les objets à l'intérieur de votre classe.
Voir ma réponse à ce pourquoi.
La méthode Reset() nécessite un entretien.
Si vous avez écrit tout le code de la manière que vous proposez, je dirais que l'ensemble de votre base de code aurait besoin d'entretien
Techniquement, vous devez modifier la deuxième ligne, de "ne JAMAIS faire cette" partie de
delete anObject
parce quefree()
ne pas appeler les destructeursOriginalL'auteur Brock Woolf
Vous ne pouvez pas appeler le constructeur de la manière indiquée par vous. Au lieu de cela, vous pouvez le faire en utilisant le placement-nouveau (comme votre code indique également):
Ce code est la garantie d'être bien défini si l'emplacement de mémoire est toujours disponible, comme il se doit dans votre cas.
(J'ai supprimé la partie sur si c'est discutable code ou pas – elle est bien définie. Arrêt complet.)
Par la voie, Brock est juste: comment la mise en œuvre de
delete
n'est pas fixe il est pas le même que d'appeler le destructeur, suivie parfree
. Toujours paire appels denew
etdelete
, ne mélangez jamais l'un avec l'autre: c'est indéfini.&
? :o) plus Sérieusement: merci; j'ai oublié queanObject
était déjà un pointeur.Pas de problème. Je upvoted lorsque vous avez modifié.
Mais si j'en ai besoin (car le pointeur sur l'objet en cours de réinitialisation, c'est de rester dans la file d'attente très longue, je ne veux pas analyser), il n'y a évidemment pas de problème, non?
Juste pour ajouter à cette réponse: La raison pour laquelle le placement de nouveaux existe, c'est parce que vous ne pouvez pas appeler un constructeur directement.
Donc, qu'arriverait-il si le placement de nouveaux ctor appel déclenche une exception? La mémoire n'est pas libéré, mais l'objet n'est pas construit, donc on ne peut pas appeler delete nous-mêmes.
OriginalL'auteur Konrad Rudolph
Remarque qu'ils ne sont pas
malloc
etfree
qui sont utilisés, maisoperator new
etoperator delete
. Aussi, à l'inverse de votre code, en utilisant une nouvelle vous êtes garantissant l'exception de sécurité. La presque l'équivalent de code serait le suivant.La réinitialisation vous proposez est valide, mais pas idiomatique. Il est difficile d'obtenir le droit, en tant que telle est généralement mal vu et découragés.
OriginalL'auteur avakar
Vous ne pouvez pas appeler le constructeur de la sorte, mais il n'y a rien de mal avec la réutilisation de la mémoire et de l'appel de placement de nouvelles, aussi longtemps que vous ne pas supprimer ou libres (libérer) de la mémoire. Je dois dire mettre à zéro un objet, comme c'est un peu louche. Je voudrais écrire un objet à être explicitement resetable, ou écrire une méthode d'échange et de l'utiliser pour le réinitialiser.
E. g.
OriginalL'auteur Logan Capaldo
Si votre objet est raisonnable d'attribution de la sémantique (et de corriger l'opérateur=), puis *anObject = AnObject() plus de sens, et est plus facile à comprendre.
OriginalL'auteur EFraim
Oui, ce que vous faites est valable la plupart du temps. [de base.la vie]p8 dit:
Si elle est légale, si vous n'avez pas de
const
ou membre de référence.Si vous n'avez pas cette garantie, vous devez utiliser
std::launder
ou utiliser le pointeur retourné par le placement de nouvelles (comme vous êtes en train de faire de toute façon) si vous souhaitez utiliser le nouvel objet:OriginalL'auteur Rakete1111
Il est de loin préférable de n'ajouter quelque chose comme une méthode Reset() de votre objet, plutôt que de jouer avec le placement de nouvelles.
Vous êtes exploitant le placement de la nouvelle fonctionnalité qui est destinée à vous permettre de contrôler l'endroit où un objet est alloué. C'est typiquement un problème uniquement si votre matériel est "spécial" de la mémoire comme une puce de mémoire flash. SI vous voulez mettre des objets dans la puce de mémoire flash, vous pouvez utiliser cette technique. La raison qu'il vous permet d'appeler explicitement le destructeur est que VOUS êtes maintenant dans le contrôle de la mémoire, de sorte que le compilateur C++ ne sais pas comment faire la désallocation de la partie de la supprimer.
Il n'est pas de sauver que vous beaucoup de code, avec une méthode de réinitialisation, vous devez définir les membres de leurs valeurs de départ. malloc() ne pas faire cela, alors vous allez avoir à écrire ce code dans le constructeur de toute façon. Il suffit de faire une fonction qui définit vos membres aux valeurs de départ, de l'appeler Reset() appeler le constructeur et aussi à partir de n'importe où ailleurs vous avez besoin.
OriginalL'auteur manovi
Pourquoi ne pas réinitialiser à l'aide de l'opérateur=()? Ce n'est pas discutable, et de loin, le plus lisible.
OriginalL'auteur David Feurle