Si je fais
struct MyStruct { ~MyStruct() { } }; void *buffer = operator new(1024); MyStruct *p = new(buffer) MyStruct(); // ... delete p; // <---------- is this okay?
3 Réponses :
[révisé] Ce n'est généralement pas d'accord, et vous ne pouvez généralement que puisque vous utilisez une nouvelle expression de placement pour créer Supprimer CODE> quelque chose qui a été obtenu avec l'expression correspondante
nouvelle code>. Sinon, il vous appartient de garantir que la fonction de translocation correspond à la fonction d'allocation (afin d'utiliser
:: Supprimer p; code> serait la solution générale plus sûre, en supposant que votre opérateur
original nouveau code> était dans l'espace de noms global). En particulier, lorsque la classe en question (ou l'une de ses classes dérivées) surchargez
nouvel opérateur code> vous devez faire attention.
* P code>, et puisqu'il n'y a pas de "expression de placement-suppression", vous devez détruire l'objet manuellement, puis relâcher la mémoire: p>
p->~MyStruct();
operator delete(buffer);
En dehors de Knee-Serk "C'est étrange et lié à la mémoire, il doit donc être ub", quelles preuves avez-vous pour cela?
@Mankarse: Supprimer p code> serait potentiellement invoquer
muntructeur :: Opérateur Supprimer CODE>, qui peut faire quelque chose de tout à fait inapproprié, WHERAS
:: Opérateur Supprimer code> est réellement appelé pour.
Vrai, mais cela ne signifie pas que vous pouvez seulement b> Supprimer code> quelque chose qui a été obtenu avec la plaine
nouvelle expression code>. Cela peut également travailler dans ces situations où vous savez que
muntructeur :: l'opérateur Supprimer code> n'existe pas. (Bien que j'accepte que cela fait d'utiliser
Supprimer code> un peu dangereux et en fait probablement une mauvaise idée dans la plupart des situations).
@Mankarse: Aussi 5.3.5 / 2: "La valeur de l'opérande de Supprimer code> peut être [...] un pointeur sur un objet non-tableau créé par une nouvelle expression précédente [.. .]. Sinon, le comportement n'est pas défini. "
@Mankarse: "comportement non défini" fait bien sûr "fait exactement ce que vous pensez que cela devrait faire". (Donc, cela pourrait fonctionner dans un cas donné, mais ce n'est généralement pas correct.)
Le placement nouveau est une forme de nouvelle expression code> (voir ma réponse ci-dessous) et une durée de vie d'un objet ne commence que lorsque son initialisation est terminée (
[basic.life] / 1 code>) , donc placement nouveau fait i> crée des objets.
Hmm, je ne suis pas convaincu de la réponse encore ... @kerreksb: Pourriez-vous élargir ce qui se passerait si opérateur Nouveau ou
Opérateur Supprimer code> était pas i> surchargé? Y aurait-il des garanties alors?
@Mehrdad: Mankarse a eu raison. S'il n'y a pas d'opérateur surchargé Supprimer code> dans la classe, c'est le type de
* p code> (le type dynamique si le destructeur est virtuel), puis
Supprimer p; code > Recherchera la fonction dans l'espace de noms global. En supposant que votre opérateur
original nouveau code> était également dans l'espace de noms global, cela devrait être correct.
@Mehrdad: Mais notez que cette conception n'est pas sûre: en ajoutant quelque chose au cours plus tard, quelqu'un pourrait casser votre code à distance et vous ne sauriez jamais. Vous pouvez vous épargner tout ce trouble en faisant la bonne chose. (La réelle i> la bonne chose de droite n'est jamais d'épeler "nouveau" dans le code de la clientèle de toute façon et utilisez plutôt quelque chose comme tous les allocateurs et Allocate_shared code> etc.)
sauf si La valeur de l'opérande de Suppr peut être ... un pointeur sur un objet non-arrayé créé par un précédent nouvelle expression em>. p>.
blockQuote> placement nouveau est un type de nouvelle expression em>. nouvelle expression i>: ... La Supprimer-expression i> invoquera le destructeur (le cas échéant) pour l'objet ... P>
... L'expression Supprimer i> appellera une fonction de distribution ... p>
blockQquote> Tant que la fonction de distribution correspond à la fonction d'allocation (qu'elle doit, tant que vous n'avez pas surchargé Supprimer p code> est équivalent à
muntruct code> a une alternative
l'opérateur supprime code>, donc votre exemple doit être bien définie avec la sémantique attendues p>
[expr.delete] / 2 code> états:. p>
[expr.new] / 1 code>: p>
      :: OPT SUB> I> Nouveau B> Nouvel Placement OPT SUB> Nouvelle-Type-ID NOUVEAU- Initializer opt sub> i>
    :: opt sub> i> nouveau b> nouveau placement opt sub> i> ( ID de type i>) nouvel initialiseur opt sub> i> p>
blockQuote> Supprimer code> est défini comme un appel au destructeur de l'objet, puis un appel à la fonction de distribution pour la mémoire.
[expr.delete] / 6,7 code>: p>
EXPLICATION CODE> pour votre classe), cela devrait-il tous être bien définie. p> p>
Hmm. Vous devez également noter que la mise en œuvre n'est pas autorisée à ajouter un remplissage entre après la valeur de retour de opérateur nouveau code>. (Ce n'est pas; C ++ 11 §5.3.4 / 10.) Même ainsi, je me sens toujours mal à l'égard de cela. Il ne semble pas y avoir un cas d'utilisation inévitable depuis
dynamic_cast
Le consensus uniforme est que le passage de la valeur de retour de l'emplacement Nouveau sur Supprimer code> n'est pas OK
après tout , le placement nouveau n'exige pas que la mémoire ait été obtenue de :: opérateur nouveau () code> en premier lieu. Le reste de cette réponse s'effondre immédiatement, avec ce malentendu fondamental supprimé.
Non, vous ne devez généralement pas appeler Supprimer (dans certains cas comme lorsque la suppression de l'opérateur est superficielle, cela peut être ok).
char *buffer = new char[1024]; MyStruct *p = new(buffer) MyStruct(); //placement new "i'm just calling constructor" p->~MyStruct(); //destroy the object. //delete p; // WHAT? even if you override operator delete it may be opaque to reader. delete [] buffer; // THIS DELETE IS OK (if you have first destroyed MyStruct)
Existe-t-il une différence dans la représentation de la mémoire résultante entre la façon dont vous avez alloué et construit l'objet contre le faire en une étape? Si oui, alors la suppression échouera probablement. Si non, alors la suppression réussira probablement. La question revient donc à la manière dont la standard spécifie le fonctionnement de
nouveau code>, pas
Supprimer code>.
J'ai testé cela avec GCC + Valgrind - et aucune erreur n'a été rapportée.