Considérez que j'ai un tableau de pointeurs déclaré comme:
myArr[i] = myObjectInstance
Et puis j'attribue des objets par
MyObject** myArr = new MyObject*[someSize] ;
Maintenant, je voulez supprimer chaque élément pointé par chaque pointeur de ce tableau. Alors, quelle est la bonne façon de faire cela?
Je ne pense pas que delete [] myArr
fonctionne.
5 Réponses :
Acctualy, delete [] myArr
a raison, car myArr
est un objet alloué dynamiquement.
Vous devrez peut-être désallouer certains myArr [i] avant si vous faites un
myArr [i] = myObjectInstance
où myObjectInstance
est alloué dynamiquement, exemple:
for (int i = 0; i < someSize; ++i) delete myArr[i];
delete myArr [i];
va planter si:
MyObject m; myArr[i] = &m;
Dans le cas où toutes les positions sont allouées dynamiquement, vous pouvez utiliser un pour libérer de la mémoire:
myArr[i] = new MyObject;
Qui fuit de la mémoire pour les objets eux-mêmes
cela dépend de la manière dont ils sont alloués.
L'OP veut explicitement supprimer chaque élément pointé par chaque pointeur de ce tableau
.
for (int i = 0; i < someSize; ++i) delete myArr[i]; That could do the trick. However you go about it, you will have to visit each element and delete it individually, and then delete the array with delete [] myArr;.But dynamically allocating arrays can be messy business. In keeping up with SO traditions, I'm going to recommend std::vector (or whatever STL container makes sense) if you are able to use it. You would still have to individually delete all elements, but now you don't have to worry about the array itself.As mentioned in the comments to your question, if you use smart pointers to each element, then you don't have to manually delete anything.
C'est exact, en supposant que myObjectInstance
était un pointeur vers MyObject
créé avec new
. Il n'y a cependant pas besoin d'indirection supplémentaire de la référence. auto i
serait suffisant.
Comment cela se compile même? myArr a une taille inconnue. J'obtiens l'attendu: erreur C2672: 'begin': aucune fonction surchargée correspondante trouvée
@sweenish vous ne pouvez pas utiliser de plage basée sur une boucle sur un tableau simple
@Kapli Vous pouvez. L'erreur est que vous ne pouvez pas l'utiliser sur un tableau alloué dynamiquement. S'il avait été sur la pile, une boucle for basée sur la plage fonctionnerait très bien. Je vais éditer. C'était un oubli.
@Jeffrey J'ai oublié qu'il s'agit d'un tableau alloué dynamiquement. Si c'était sur la pile, les boucles for basées sur la plage fonctionnent très bien.
@eerorika Depuis la copie fournie est toujours un pointeur vers la même ressource dynamique, vrai. J'ai juste l'habitude d'ajouter la référence lors de modifications directes.
Supprimez d'abord chaque objet, puis le tableau entier:
for(int i = 0; i < someSize; i++) { delete myArr[i]; } delete[] myArr;
Il va planter si MyObject m; myArr [0] = & m;
L'OP a demandé "Je veux supprimer chaque élément pointé par chaque pointeur de ce tableau.". C'est ce que fait le code ci-dessus. Je fais confiance à l'OP pour mettre l'objet alloué dyunamiquement dans la liste.
Est agréable de pointer ce cas, il peut être confus. (Ce n'est pas moi qui ai voté contre)
@Jeffrey Votre confiance ne sera pas brisée
Et si tous les éléments ne sont pas alloués dynamiquement?
Ce serait une très mauvaise idée de stocker dans le même tableau les pointeurs vers les éléments alloués dynamiquement et ceux alloués non dynamiquement. Si vous avez les deux, ayez deux tableaux, avec des noms significatifs, et supprimez les éléments du bon uniquement.
Vous pouvez utiliser l'algorithme standard std :: for_each
et l'objet fonction std :: default_delete
.
Voici un programme de démonstration
std::for_each( std::reverse_iterator<A **>( p + N ), std::reverse_iterator<A **>( p ), std::default_delete<A>() );
Sa sortie est
9: ~A() 8: ~A() 7: ~A() 6: ~A() 5: ~A() 4: ~A() 3: ~A() 2: ~A() 1: ~A() 0: ~A()
Si vous souhaitez supprimer les éléments du tableau dans l'ordre inverse par rapport à l'ordre de leur création, vous peut écrire
#include <iostream> #include <memory> #include <algorithm> struct A { static size_t i; A() { i++; } ~A() { std::cout << --i << ": ~A()\n"; } }; size_t A::i = 0; int main() { const size_t N = 10; A **p = new A *[N]; for ( size_t i = 0; i < N; i++ ) { p[i] = new A(); } std::for_each( p, p + N, std::default_delete<A>() ); delete []p; return 0; }
Voté à la hausse, car c'est un C ++ très moderne - ish. Mais je trouve que for_each et default_delete sont un peu avancés, alors qu'un simple for
pourrait faire l'affaire. Cela dépend du style, je suppose.
Supposons que tous les myObjectInstance
sont des pointeurs vers des objets alloués au tas (sinon, voir la réponse de @ Joà £ oPaulo), et pas de new
personnalisé ou delete
est impliqué.
for (size_t idx = 0; idx < someSize; ++idx) delete myArr[idx]; delete[] myArr;
Quel est le piège potentiel?
Eh bien, il y en a beaucoup. Et si seuls certains des éléments du tableau étaient initialisés? L'autre serait dans un état indéterminé et leur suppression entraînerait un comportement indéfini.
Et si plusieurs éléments du tableau pointent vers le même objet? Ensuite, vous essayez de supprimer un objet plusieurs fois. Cela conduit également à un comportement indéfini.
Cela ne signifie pas que vous ne pouvez pas utiliser cette méthode naïve, cela vous rappelle juste quelques pré-conditions:
nullptr
(la suppression de nullptr
est sûre).
std :: vector> myArr;
et prenez-le à partir de là ...La bonne façon est d'utiliser un vecteur de
unique_ptr
au lieu d'essayer de gérer la mémoire manuellement.Je sais que c'est recommandé. Je ne peux pas utiliser de vecteur, et je ne peux utiliser que des tableaux et de la mémoire en plus.