2010-07-18 8 views
1

J'ai une très grande classe étalée qui est essentiellement une liste chaînée tridimensionnelle très artificielle. Je veux être capable de le «compiler», ce qui signifie que je veux terminer la liste, de sorte que seuls les accès en lecture puissent être faits, puis déplacer tous les éléments dans des espaces mémoire contigus. Ma solution brute est la suivante:Je fais des choses géniales avec le placement nouveau, et les choses échouent. Solutions de contournement?

#include <new> 
... 
MyListNode* pool = new MyListNode[length]; 
new(&pool[position]) MyListNode(); 

Le problème est que j'ai essentiellement deux classes, l'une attribuée avec nouvelle et l'autre alloué avec cette méthode ici, et quand je tente de supprimer l'un des objets attribués par la La méthode ci-dessus, glibc tue le programme à cause d'un pointeur invalide. La solution naturelle est de créer deux classes, et d'utiliser simplement le polymorphisme d'exécution pour fournir une interface mais deux implémentation, etc. Est-il possible que le standard de mémoire en C++ permette ce type de pokery jiggery?

+0

Avez-vous un exemple court mais complet qui reproduit le problème? –

Répondre

2

Appellez-vous delete sur l'un des objets de votre tableau? Ou appelez-vous manuellement le destructeur pour refléter le placement nouveau?

Étant donné que vous avez un appel au non-placement nouveau, vous ne devriez avoir qu'un seul appel à supprimer. Et puisque vous avez n-calls à placement-new, vous devez appeler manuellement le destructeur n fois.

Donc, vous voudrez peut-être quelque chose comme ceci:

// Allocate an array of chars instead of an array of MyListNode. Since we 
// are going to use placement new, this is necessary if MyListNode has a 
// a default constructor 
MyListNode* pool = static_cast<MyListNode *>(new char[sizeof(MyListNode) * length); 
for (size_t position = 0; position < length; ++position) 
    new(&pool[position]) MyListNode(); 

... 

for (position = 0; position < length; ++position) 
    pool[position].~MyListNode() 

delete[] static_cast<char *>(pool); 
+0

Cela provoque un comportement indéfini. 'delete [] pool' est incorrect car' pool' a le type 'MyListNode *' mais le tableau original a été alloué en tant que tableau de 'char'. De plus, les destructeurs 'MyListNode' ont déjà été appelés explicitement dans la boucle précédente. 'operator delete []' serait la fonction correcte à utiliser pour libérer la mémoire. –

+0

@CharlesBailey - merci. J'ai décidé de corriger en transposant 'char *' pour refléter l'allocation. –

+0

Désolé, mon commentaire était incomplet. Je voulais dire que vous devriez utiliser 'operator new []' pour allouer aussi bien que je ne l'ai pas explicitement déclaré. Le problème que j'ai avec votre approche est que techniquement vous avez déjà terminé la vie des objets 'char' en réutilisant leur stockage pour un type différent d'objet. C'est pourquoi je privilégie l'approche des fonctions de stockage brutes. –

3

La possibilité évidente serait de vérifier l'adresse de l'objet, et de ne l'effacer que si elle se trouve en dehors de votre piscine. Si je le faisais, je pense que je surchargerais probablement operator new pour la classe, et l'allouerais toujours l'espace de votre piscine. De cette façon, vous obtenez votre allocation contiguë sans copier, et vos objets sont attribués uniformément afin que vous puissiez les supprimer uniformément.

Questions connexes