Tableau de pointeurs C++: supprimer ou supprimer []?
coder le code suivant:
class Foo
{
Monster* monsters[6];
Foo()
{
for (int i = 0; i < 6; i++)
{
monsters[i] = new Monster();
}
}
virtual ~Foo();
}
Quel est le bon destructeur?
ceci:
Foo::~Foo()
{
delete [] monsters;
}
ou:
Foo::~Foo()
{
for (int i = 0; i < 6; i++)
{
delete monsters[i];
}
}
j'ai actuellement le constructeur le plus haut et tout fonctionne bien, mais bien sûr je ne peux pas voir s'il se trouve que ça fuit...
personnellement, je pense que la deuxième version est beaucoup plus logique compte tenu de ce que je fais. De toute façon, Quelle est la "bonne" façon de faire ça?
8 réponses
delete[] monsters;
est incorrect parce que monsters
n'est pas un pointeur vers un tableau alloué dynamiquement, c' un tableau de pointeurs. En tant que membre de classe, il sera automatiquement détruit lorsque l'instance de classe sera détruite.
votre autre implémentation est la bonne puisque les pointeurs dans le tableau pointent vers Monster
objets.
notez qu'avec votre stratégie actuelle d'allocation de mémoire vous voulez probablement déclarer votre posséder le constructeur de copie et l'opérateur de copie-cession pour que la copie involontaire ne provoque pas de doubles suppressions. (Si vous voulez empêcher la copie, vous pouvez les déclarer comme privées et ne pas réellement les mettre en œuvre.)
new
vous devez utiliser delete
. new[]
utiliser delete[]
. Votre deuxième variante est correcte.
le second est correct dans les circonstances (enfin, le moins mal).
Edit: "le moins faux", comme dans le code original ne montre aucune bonne raison d'utiliser new
ou delete
en premier lieu, donc vous devriez probablement juste utiliser:
std::vector<Monster> monsters;
le résultat sera un code plus simple et une séparation plus claire des responsabilités.
#include "stdafx.h"
#include <iostream>
using namespace std;
class A
{
private:
int m_id;
static int count;
public:
A() {count++; m_id = count;}
A(int id) { m_id = id; }
~A() {cout<< "Destructor A " <<m_id<<endl; }
};
int A::count = 0;
void f1()
{
A* arr = new A[10];
//delete operate only one constructor, and crash!
delete arr;
//delete[] arr;
}
int main()
{
f1();
system("PAUSE");
return 0;
}
La sortie est: Destructeur A 1 et puis il s'effondre(Expression: _block_type_is_valid (phead - nBlockUse)).
nous devons utiliser: delete[] arr; becuse il est supprimer l'ensemble du tableau et pas seulement une cellule!
essayez d'utiliser delete[] arr; la sortie est: Destructeur A 10 Destructeur A 9 Destructeur A 8 Destructeur A 7 Destructeur A 6 Destructeur A 5 Destructeur A 4 Destructeur A 3 Destructeur D'Un Deux Destructeur A 1
le même principe s'applique à un tableau de pointeurs:
void f2()
{
A** arr = new A*[10];
for(int i = 0; i < 10; i++)
{
arr[i] = new A(i);
}
for(int i = 0; i < 10; i++)
{
delete arr[i];//delete the A object allocations.
}
delete[] arr;//delete the array of pointers
}
si on utilise delete arr au lieu de delete [] arr. il ne supprimera pas les pointeurs entiers dans le tableau => fuite de mémoire des objets pointeurs!
delete[] monsters
est définitivement faux. Mon tas débogueur affiche la sortie suivante:
allocated non-array memory at 0x3e38f0 (20 bytes)
allocated non-array memory at 0x3e3920 (20 bytes)
allocated non-array memory at 0x3e3950 (20 bytes)
allocated non-array memory at 0x3e3980 (20 bytes)
allocated non-array memory at 0x3e39b0 (20 bytes)
allocated non-array memory at 0x3e39e0 (20 bytes)
releasing array memory at 0x22ff38
comme vous pouvez le voir, vous essayez de libérer avec la mauvaise forme de delete (non-array vs. array), et le pointeur 0x22ff38 n'a jamais été retourné par un appel à new. La deuxième version affiche le résultat:
[allocations omitted for brevity]
releasing non-array memory at 0x3e38f0
releasing non-array memory at 0x3e3920
releasing non-array memory at 0x3e3950
releasing non-array memory at 0x3e3980
releasing non-array memory at 0x3e39b0
releasing non-array memory at 0x3e39e0
quoi qu'il en soit, je préfère une conception où la mise en œuvre manuelle du destructeur n'est pas nécessaire pour commencer.
#include <array>
#include <memory>
class Foo
{
std::array<std::shared_ptr<Monster>, 6> monsters;
Foo()
{
for (int i = 0; i < 6; ++i)
{
monsters[i].reset(new Monster());
}
}
virtual ~Foo()
{
// nothing to do manually
}
};
Votre deuxième exemple est correct; vous n'avez pas besoin de supprimer le monsters
tableau lui-même, juste les objets individuels que vous avez créés.
Vous supprimez chaque pointeur individuellement, et vous supprimez l'ensemble de la matrice. Assurez-vous que vous avez défini un destructeur approprié pour les classes stockées dans le tableau, sinon vous ne pouvez pas être sûr que les objets sont nettoyés correctement. Assurez-vous que tous vos destructeurs sont virtuels, afin qu'ils se comportent correctement lorsqu'il est utilisé avec l'héritage.
Il ferait de sens si votre code est comme ceci:
#include <iostream>
using namespace std;
class Monster
{
public:
Monster() { cout << "Monster!" << endl; }
virtual ~Monster() { cout << "Monster Died" << endl; }
};
int main(int argc, const char* argv[])
{
Monster *mon = new Monster[6];
delete [] mon;
return 0;
}