Est-il sécuritaire de supprimer un vide pointeur?
Supposons que j'ai le code suivant:
void* my_alloc (size_t size)
{
return new char [size];
}
void my_free (void* ptr)
{
delete [] ptr;
}
Est-il sécuritaire? Ou doit ptr
être jeté à char*
avant la suppression?
- Pourquoi faites-vous la gestion de la mémoire vous-même? Quelle structure de données êtes-vous créer? Avoir besoin de faire explicite de gestion de la mémoire est assez rare en C++, vous devez généralement utiliser les classes qui en chargera pour vous de la STL (ou de coup de pouce dans une pincée).
- Juste pour les gens qui lisent, j'utilise void* variables comme paramètres pour mon fils en gagner c++ ( voir _beginthreadex ). Habituellement, ils sont acutally pointant vers des classes.
- Dans ce cas, il est d'un usage général wrapper pour new/delete, qui pouvait contenir le suivi de l'allocation des statistiques, par une optimisation de la mémoire de la piscine. Dans d'autres cas, j'ai vu des pointeurs d'objet mal stocké comme void* variables de membre, et supprimé de manière incorrecte dans le destructeur sans coulée de retour pour le type d'objet approprié. J'ai donc été curieux au sujet de la sécurité/pièges.
- Pour un usage général wrapper pour new/delete, vous pouvez surcharger le nouveau/supprimer des opérateurs. En fonction de l'environnement que vous utilisez, vous avez probablement des crochets dans la gestion de la mémoire pour le suivi des allocations. Si vous vous retrouvez dans une situation où vous ne savez pas ce que votre sont la suppression, le prendre comme un indice que votre conception est sous-optimale et les besoins de refactoring.
- Puisque vous êtes déjà emballage de la répartition et de la destruction, vous pouvez facilement moulé avec pas de frais généraux.
- Pouvez penser à des charges de raisons pourquoi vous voulez le faire en c++, par exemple, disons que vous avez une base de données de vos besoins du programme, il a été exporté dans un format binaire, et vous voulez être en mesure de charger cette base de données traitées dans un seul bloc de mémoire... ou si vous avez votre propre système de fichiers virtuel (bien que j'attends de ce genre de techniques sont probablement plus utile dans le développement d'un jeu où la performance est critique
- Je pense qu'il y a trop de questionner la question au lieu d'y répondre. (Et pas seulement ici, mais dans l'ensemble DONC)
- Mais sérieusement, @Andrew suffit d'utiliser
malloc
etfree
directement. Que contient implicitement le fait que le constructeur/destructeur ne sera pas appelé (comme les réponses ci-dessous le dire) sur ce que sous-tend quevoid*
pointeur. - Depuis le char n'a pas de destructeur, ce sera à l'abri. malloc/free serait plus rapide, mais alors vous perdez std::bad_alloc.
- J'utilise un void* en tant que contexte qui est passé pour moi en code C# et dont le type sera en un tiers de code C++ mise en œuvre d'une base de classe de plugin que j'offre. Dans mon cas, tout ce qui était nécessaire était de faire
delete (MyPluginBase*) aPointer
et de s'assurer queMyPlugin
a un destructeur virtuel.
Vous devez vous connecter pour publier un commentaire.
Il dépend de "coffre-fort". Il fonctionne habituellement parce que l'information est stockée avec le pointeur sur l'allocation elle-même, de sorte que le deallocator pouvez le retourner à la bonne place. En ce sens, il est "sûr" aussi longtemps que votre allocateur utilise de la frontière interne des balises. (Beaucoup le font.)
Cependant, comme mentionné ci-dessus, la suppression d'un pointeur void ne vais pas appeler les destructeurs, qui peut être un problème. En ce sens, il n'est pas "sans danger".
Il n'y a aucune bonne raison pour faire ce que vous faites de la façon dont vous le faites. Si vous voulez écrire vos propres fonctions de libération de la mémoire, vous pouvez utiliser les modèles de fonction pour générer des fonctions avec le type correct. Une bonne raison de le faire est de générer de la piscine allocateurs, qui peut être extrêmement efficace pour des types spécifiques.
Comme mentionné dans d'autres réponses, c'est un comportement indéfini en C++. En général, il est bon d'éviter un comportement indéfini, bien que le sujet lui-même est complexe et rempli avec des opinions contradictoires.
La suppression par l'intermédiaire d'un pointeur void est pas défini par la Norme C++ - voir section 5.3.5/3:
Et sa note de bas de page:
.
Ce n'est pas une bonne idée et pas quelque chose que vous faites en C++. Vous perdez vos informations de type pour aucune raison.
Votre destructeur ne sera pas appelé sur les objets de votre groupe que vous souhaitez supprimer lorsque vous appelez pour des types primitifs.
En revanche, vous pouvez remplacer new/delete.
La suppression de l'void* sera probablement libérer votre mémoire correctement par hasard, mais c'est faux, car les résultats ne sont pas définis.
Si, pour une raison inconnue de moi, vous avez besoin de stocker le pointeur de la souris dans un void* puis gratuitement, vous devez utiliser malloc et free.
La suppression d'un pointeur void est dangereux parce que les destructeurs ne sera pas appelé à la valeur qu'elle renvoie. Cela peut résultat en mémoire /ressources des fuites dans votre application.
La question n'a pas de sens. Votre confusion peut être en partie due à la bâclée langue les gens utilisent souvent avec
delete
:Vous utilisez
delete
pour détruire un objet qui a été allouée dynamiquement. Le faire le faire, vous formez un supprimer l'expression avec un un pointeur vers cet objet. Vous n'avez jamais "supprimer un pointeur". Ce que vous avez vraiment à faire est de "supprimer un objet qui est identifié par son adresse".Nous voyons maintenant pourquoi la question n'a pas de sens: Un pointeur void n'est pas l'adresse d'un objet". C'est juste une adresse, sans aucune sémantique. Il peut viennent de l'adresse d'un objet réel, mais que l'information est perdue, parce qu'il a été codé dans le type de l'original pointeur. Le seul moyen de restaurer un pointeur d'objet est de jeter le vide pointeur de retour d'un pointeur d'objet (ce qui oblige l'auteur à savoir ce que le pointeur de moyens).
void
lui-même est un type incomplète et donc jamais le type d'un objet, et un pointeur void ne peut jamais être utilisé pour identifier un objet. (Les objets sont identifiés conjointement par leur type et leur adresse.)delete
peut être une valeur de pointeur null, un pointeur vers un tableau non objet créé par un précédent nouvelle-expression, ou un pointeur vers un sous-objet représentant une classe de base d'un tel objet. Si pas, le comportement est indéfini." Donc, si un compilateur accepte votre code sans un diagnostic, ce n'est rien, mais un bug du compilateur...delete void_pointer
. C'est un comportement indéfini. Les programmeurs doivent de ne jamais invoquer un comportement indéfini, même si la réponse semble à ce que le programmeur voulait faire.Parce que char n'a pas de spécial destructeur de la logique. CELA ne fonctionnera pas.
Le d'ctor ne sera pas appelée.
Si vous souhaitez utiliser void*, pourquoi ne pas utiliser simplement la fonction malloc/free? new/delete est plus que juste de la gestion de la mémoire. Fondamentalement, les appels de new/delete un constructeur/destructeur et il y a plus de choses qui se passent. Si vous venez d'utiliser les haut-types (type char*) et de les supprimer par le biais de void*, il pourrait fonctionner, mais encore il n'est pas recommandé. La ligne de fond est l'utilisation de malloc/free si vous souhaitez utiliser void*. Sinon, vous pouvez utiliser le modèle de fonctions pour votre commodité.
Si vous devez vraiment le faire, pourquoi ne pas couper l'homme du milieu (la
new
etdelete
opérateurs) et d'appeler le mondialoperator new
etoperator delete
directement? (Bien sûr, si vous essayez de instrument lanew
etdelete
opérateurs, vous devriez ré-écrireoperator new
etoperator delete
.)Noter que, contrairement à
malloc()
,operator new
jettestd::bad_alloc
en cas d'échec (ou appelle lanew_handler
si l'on est inscrit).Beaucoup de gens ont déjà commenté en disant que non, il n'est pas sûr de supprimer un vide pointeur. Je suis d'accord avec cela, mais je voulais aussi ajouter que si vous travaillez avec des pointeurs void afin d'allouer des tableaux contigus ou quelque chose de similaire, que vous pouvez faire cela avec
new
de sorte que vous serez en mesure d'utiliserdelete
en toute sécurité (avec, hum, un peu de travail supplémentaire). Ceci est fait par l'attribution d'un vide pointeur vers la zone mémoire (appelé une "arène") et puis fournit le pointeur à l'arène de nouveau. Voir cet article dans le C++ FAQ. C'est une approche commune pour la mise en œuvre des pools de mémoire en C++.N'est pas une raison pour le faire.
Tout d'abord, si vous ne connaissez pas la type des données, et tout ce que vous savez est que c'est
void*
, alors vous devriez vraiment juste être le traitement de données comme un sans type blob de données binaires (unsigned char*
), et l'utilisationmalloc
/free
de traiter avec elle. C'est parfois nécessaire pour des choses comme les données de forme d'onde et le voulez, où vous devez passer autour devoid*
pointeurs C api. C'est très bien.Si vous ne connaître le type de données (c'est à dire qu'il a un ctor/dtor), mais pour une raison que vous vous retrouviez avec une
void*
pointeur (pour quelque raison que ce soit vous avez) alors vous devriez vraiment jeter en arrière pour le genre vous savez qu'elle est, et d'appelerdelete
sur elle.J'ai utilisé void*, (aka les types inconnus) dans mon cadre de tandis que dans le code de la réflexion et autres exploits de l'ambiguïté, et jusqu'à présent, j'ai eu aucun problèmes (fuite de mémoire, des violations d'accès, etc.) de toute compilateurs. Seulement mises en garde en raison de la non-standard.
C'est parfaitement logique pour supprimer une inconnue (void*). Juste assurez-vous que le pointeur suit ces directives, ou il peut arrêter de faire sens:
1) L'inconnu pointeur ne doit pas pointer vers un type qui a un trivial déconstructeur, et donc quand coulé comme une inconnue pointeur elle ne doit JAMAIS ÊTRE SUPPRIMÉ. Seulement supprimer l'inconnu pointeur APRÈS la coulée de nouveau dans le type d'ORIGINE.
2) Est l'instance référencée comme une inconnue pointeur dans la pile lié ou d'un segment lié mémoire? Si l'inconnu pointeur de références d'une instance sur la pile, alors il ne devrait JAMAIS ÊTRE SUPPRIMÉ!
3) Êtes-vous 100% positif de l'inconnu pointeur est une région de mémoire valide? Non, alors il ne devrait JAMAIS ÊTRE DELTED!
En tout, il y a très peu de travail qui peut être réalisé à l'aide d'un inconnu (void*) type de pointeur. Cependant, indirectement, le void* est un grand atout pour les développeurs C++ compter sur lorsque les données de l'ambiguïté est nécessaire.
Si vous voulez juste un tampon, l'utilisation de malloc/free.
Si vous devez utiliser de new/delete, envisager un trivial classe wrapper:
Pour le cas particulier de char.
char est un type intrinsèque qui n'a pas de destructeur. Si les fuites d'arguments est un moot un.
sizeof(char) est généralement donc il n'y a pas d'alignement argument soit. Dans le cas d'une rare plate-forme où l'sizeof(char) n'est pas un, ils allouer de la mémoire aligné assez pour leur char. Si l'alignement argument est également un moot un.
malloc/free serait plus rapide sur cette affaire. Mais vous perdez std::bad_alloc et de vérifier le résultat de la fonction malloc. L'appel de la nouvelle et supprimer des opérateurs peut être mieux comme ça contourner l'homme du milieu.