Stack svolgendo in caso di eccezioni strutturate
-
03-07-2019 - |
Domanda
Questa domanda fornisce maggiore chiarezza sul problema descritto qui . Ho fatto qualche indagine in più e ho scoperto che lo svolgersi dello stack non sta avvenendo nel seguente pezzo di codice:
class One
{
public:
int x ;
};
class Wrapper
{
public:
Wrapper(CString csText):mcsText(csText)
{
CString csTempText;
csTempText.Format("Wrapper constructor :: %s\n", mcsText);
OutputDebugString(csTempText);
}
~Wrapper()
{
CString csTempText;
csTempText.Format("Wrapper destructor :: %s\n", mcsText);
OutputDebugString(csTempText);
}
CString mcsText;
};
class Test
{
public:
void notifyError()
{
try
{
int x = 10;
}
catch(...) {}
}
void OnRecvBuffer()
{
try
{
Wrapper a("AddRef");
One* p = NULL;
p->x = 10;
}
catch(...)
{
notifyError();
}
}
};
int main()
{
Test* pTest = new Test;
pTest->OnRecvBuffer();
OutputDebugString("Test");
}
Ho compilato questo codice usando il compilatore VC6 SP5 e l'output è " Costruttore di wrapper :: AddRef !!! " (ovvero il distruttore dell'oggetto wrapper che è stato costruito sullo stack non viene chiamato. È questo il comportamento previsto? O è un bug con il compilatore VC? Posso usare alcuni flag del compilatore in modo che lo svolgersi dello stack avvenga in questo caso?
Soluzione
Se si desidera utilizzare SEH, è necessario utilizzare la funzione _set_se_translator e l'opzione del compilatore / EHa.
Altri suggerimenti
Lo standard C ++ non fornisce nulla su cui lavorare in caso di comportamento indefinito. Anche se lo fa la SM. Questa è una cosa specifica della piattaforma, quindi attenzione. Alcune di queste eccezioni in virgola mobile vengono trasformate in eccezioni Win32 che è possibile tentare di rilevare con _set_se_translator ()
. Il problema è che puoi rilevare le eccezioni di Win32 ma il tuo stack non verrà srotolato correttamente. Almeno questo non è qualcosa su cui puoi scommettere la tua vita. In che consiste l'inutilità dell'esercizio.
Aggiornamento: l'eccezione viene generata intenzionalmente per controllare lo svolgimento dello stack. La domanda è: perché il distruttore della classe Wrapper non viene chiamato. - Naveen
In questo caso, non farlo. Esistono modi migliori per generare eccezioni rispetto a Undefined Behaviour.
per esempio:
void OnRecvBuffer()
{
try
{
Wrapper a("AddRef");
throw 42; // this'll throw an exception without invoking UB
}
catch(...)
{
notifyError();
}
}
Non è possibile dereferenziare un puntatore NULL. Stai invocando Undefined Behaviour qui:
One* p = NULL;
p->x = 10;
Dopo quella linea tutte le scommesse sono spente e potresti averci ucciso tutti;)
p
è un puntatore a un oggetto One
. Dovrebbe contenere l'indirizzo di un oggetto One
. Lo hai inizializzato su 0 - non esiste alcun oggetto all'indirizzo 0. 0 non è un indirizzo valido per nessun oggetto (questo è garantito dallo standard).
Poiché l'eccezione regolare C ++ non gestisce questo tipo di eccezione, è necessario utilizzare SEH che non conosce nulla sull'app e non si svolge.
Questo è un comportamento indefinito:
One* p = NULL;
p->x = 10;
A questo punto l'applicazione è libera di bloccarsi senza srotolare lo stack.
Se si desidera testare lo svolgimento dello stack, sostituirlo con:
throw 42; // Life the Universe and Everything thrown away
Non dovresti allocare dinamicamente tutti i tuoi oggetti, questo è C ++ non Java!
int main()
{
Test pTest; // Note the lack of new!
pTest.OnRecvBuffer();
OutputDebugString("Test");
}