Ho un codice che si sta bloccando in un sistema di grandi dimensioni. Tuttavia, il codice si riduce essenzialmente al seguente pseudo-codice. Ho rimosso gran parte dei dettagli, poiché ho cercato di ridurlo alle ossa nude; Non penso che per questo manchi qualcosa di cruciale.Perché il vettore che elimina il distruttore viene chiamato come risultato di un'eliminazione scalare?
// in a DLL:
#ifdef _DLL
#define DLLEXP __declspec(dllexport)
#else
#define DLLEXP __declspec(dllimport)
#endif
class DLLEXP MyClass // base class; virtual
{
public:
MyClass() {};
virtual ~MyClass() {};
some_method() = 0; // pure virtual
// no member data
};
class DLLEXP MyClassImp : public MyClass
{
public:
MyClassImp(some_parameters)
{
// some assignments...
}
virtual ~MyClassImp() {};
private:
// some member data...
};
e:
// in the EXE:
MyClassImp* myObj = new MyClassImp (some_arguments); // scalar new
// ... and literally next (as part of my cutting-down)...
delete myObj; // scalar delete
Nota che corrispondono scalari scalare new e delete vengono utilizzati.
In un build di debug in Visual Studio (2008 Pro), in < dbgheap.c di Microsoft>, la seguente asserzione fallisce:
_ASSERTE(_CrtIsValidHeapPointer(pUserData));
Nella parte superiore dello stack sono i seguenti elementi:
mydll_d.dll!operator delete()
mydll_d.dll!MyClassImp::`vector deleting destructor'()
penso che questo dovrebbe essere
mydll_d.dll!MyClassImp::`scalar deleting destructor'()
Cioè, il programma si comporta come se avessi scritto
MyClassImp* myObj = new MyClassImp (some_arguments);
delete[] newObj; // array delete
L'indirizzo in pUserData
è quello di myObj
stesso (al contrario di un membro). La memoria per quell'indirizzo assomiglia a questo:
... FD FD FD FD
(address here)
VV VV VV VV MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
FD FD FD FD AB AB AB AB AB AB AB AB EE FE EE FE
...
dove i quattro VV
s sono presumibilmente l'indirizzo della tabella di funzione virtuale, il MM...MM
è dati utente riconoscibile, e gli altri byte sono diversi marcatori speciali PUT in posizione dal debugger (ad esempio, gli FD FD
s sono "byte di guardia" attorno all'archivio dell'oggetto).
Poco prima dell'asserzione, vedo la modifica VV
s, e mi chiedo se ciò è dovuto a un passaggio alla tabella delle funzioni virtuali della classe base.
Sono a conoscenza del problema del livello sbagliato nella gerarchia di classi in fase di distruzione. Questo non è il problema qui; i miei distruttori sono tutti virtuali.
Rilevo pagina "BUG: operatore errato Elimina Chiamato per la Classe esportato" di Microsoft http://support.microsoft.com/kb/122675 ma che sembra essere per quanto riguarda l'eseguibile sbagliato (con il mucchio sbagliato) il tentativo di assumersi la responsabilità per la distruzione dei dati.
Nel mio caso, sembra che sia stato applicato il "sapore" errato di eliminazione del distruttore: , vale a dire vettoriale anziché scalare.
Sono in procinto di provare a produrre codice di riduzione minimo che presenta ancora il problema.
Tuttavia, qualsiasi suggerimento o suggerimento su come approfondire questo problema sarebbe molto apprezzato.
Forse il più grande indizio qui è lo mydll_d.dll!operator delete()
in pila. Devo aspettarmi che questo sia myexe_d.exe!operator delete()
, indicando che gli DLLEXP
s sono stati "persi"?
Suppongo che questa potrebbe essere un'istanza di una doppia eliminazione (ma non la penso così).
C'è un buon riferimento che posso leggere per quanto riguarda gli assegni _CrtIsValidHeapPointer
?
Nel MyClassImp, il ctor e dtor sono probabilmente chiamati MyClassImp e non MyClass, non è vero? – Calvin1602
Oh, e puoi F11 nel nuovo()? Qual é ? – Calvin1602
@ Calvin1602 [1] grazie, sì, l'ho corretto ora. [2] il ten che viene chiamato è quello di 'MyClassImp' dopo/durante il quale viene chiamato quello di' MyClass'. – Rhubbarb