2010-01-11 12 views
0

Fondamentalement, j'ai une classe virtuelle pure Base, et une classe concrète Derived qui hérite de Base. J'alloue ensuite un morceau de mémoire et le traite comme un tableau de Derived via un simple casting. Ensuite, je remplis le tableau en utilisant =. Enfin, je parcourt le tableau en essayant d'appeler la méthode virtuelle GetIndex déclarée dans Base et définie dans Derived. Le problème est que je finis par obtenir une exception de violation d'accès en essayant de lire le pointeur vers la vtable pour Base (dans le débogage de Visual Studio, cela est affiché comme __vfptr, et il est toujours 0xbaadf00d).Allocation d'un tableau de Dérivé sans nouveau []: Pointer to Base vtable est mauvais

Voici un exemple simple du problème que je rencontrais:

#include "stdafx.h" 
#include "windows.h" 

struct Base 
{ 
    virtual int GetIndex() const = 0; 
}; 

struct Derived : public Base 
{ 
    int index; 

    Derived() 
    { 
     static int test = 0; 
     index = test++; 
    } 

    int GetIndex() const 
    { 
     return index; 
    } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    int count = 4; 
    // Also fails with malloc 
    Derived* pDerived = (Derived*)HeapAlloc(GetProcessHeap(), 0, sizeof(Derived) * count); 

    for (int i = 0; i < count; i++) 
    { 
     Derived t; 
     pDerived[i] = t; 
    } 

    // Should print 0 1 2 3 
    for (int i = 0; i < count; i++) 
    { 
     Base& lc = pDerived[i]; 
     printf("%d\n", lc.GetIndex()); // FAIL! 
    } 
    return 0; 
} 

Ce problème se produit uniquement lors de l'allocation de la mémoire via HeapAlloc ou malloc; Si new [] est utilisé, cela fonctionne bien. (En outre, le cstor est appelé 4 fois précédemment, de sorte que la sortie est 4 5 6 7.)

+0

À titre de référence, ceci a été résolu en remplaçant: Dérivé t; pDérivée [i] = t; avec: nouveau (& pDerived [i]) Dérivé(); – iano

Répondre

9

Si vous allouez de la mémoire sans new vous devez toujours appeler le constructeur manuellement avec placement new et le destructor avec x->~Derived();

0

Je pense que dans la première boucle, vous créez un objet sans nouveau. Ce qui signifie que le contexte de cet objet est votre boucle for. Cette variable n'existe plus lorsque vous quittez la boucle for.

1

Si vous souhaitez utiliser un allocateur en plus de la valeur par défaut de C++, vous devez définir votre propre opérateur new plutôt que d'essayer d'appeler le constructeur à chaque fois.

void *operator new[](size_t block_size, HANDLE heap) { 
    return HeapAlloc(heap, 0, block_size); 
} 

...

Derived *pDerived = new(GetProcessHeap()) Derived[ count ]; 

Détails dépendent de ce que vous voulez qu'il soit le chemin par défaut d'allocation Derived et si elle a vraiment besoin de paramètres.

Vous devez toujours faire attention si free() ne peut pas libérer la mémoire que vous avez. Ensuite, le delete par défaut ne fonctionnera pas, et vous devez soit créer Derived::operator delete ou écrire votre propre fonction qui appelle object->~Derived().