eine Reihe von neuen, ohne Abgeleitet Zuteilen []: Zeiger auf Basis VTable ist schlecht
-
20-09-2019 - |
Frage
Grundsätzlich habe ich eine reine virtuelle Klasse Basis und eine konkrete Klasse abgeleitet, die erbt von Base. I zuzuteilen dann ein Stück Speicher und behandle es als eine Anordnung von über einen einfachen Guss abgeleitet. Dann fülle ich das Array = verwenden. Schließlich habe ich Schleife durch das Array und versucht, die virtuelle Methode GetIndex zu nennen, die in der Base und definiert in Abgeleitet.
deklariertDas Problem ist, dass ich eine Zugriffsverletzung Ausnahme am Ende immer versuchen, den Zeiger auf die VTable für Base zu lesen (in Visual Studio Debuggen, wird dies als __vfptr gezeigt, und es ist immer 0xbaadf00d).
Im Anschluss ist ein einfaches Beispiel für das Problem, das mir begegnet ist:
#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;
}
Dieses Verhalten tritt nur, wenn Sie den Speicher über HeapAlloc oder malloc zuzuordnen; wenn neue [] verwendet wird, funktioniert es gut. (Außerdem wird die cstor 4mal zuvor genannt, so dass der Ausgang 4 5 6 7 ist.)
Lösung
Wenn Sie Speicher ohne new
zuweisen Sie müssen immer den Konstruktor aufrufen manuell mit Platzierung neuer und die destructor mit x->~Derived();
Andere Tipps
Wenn Sie eine allocator neben C ++ 's Standard verwenden möchten, sollten Sie Ihre eigenen Operator neu anstatt zu versuchen, definieren zu erinnern, den Konstruktor jedes Mal anzurufen.
void *operator new[]( size_t block_size, HANDLE heap ) {
return HeapAlloc( heap, 0, block_size );
}
...
Derived *pDerived = new( GetProcessHeap() ) Derived[ count ];
Details davon abhängen, ob Sie es wollen, dass der Standard-Weg, um Derived
der Aufteilung und ob es wirklich braucht Parameter.
Sie müssen noch vorsichtig sein, wenn free()
nicht den Speicher, den Sie bekam befreien kann. Dann wird die Standard delete
wird nicht funktionieren, und Sie sollten entweder Derived::operator delete
erstellen oder eigene Funktion schreiben, die object->~Derived()
nennt.
ich denke, innerhalb der ersten Schleife für Sie ohne neu Objekt erstellen. Was bedeutet, dass der Kontext dieses Objekts ist Ihre for-Schleife. Diese Variable ist nicht mehr vorhanden, wenn Sie die for-Schleife zu beenden.