Pilha desenrolar em caso de exceções estruturadas
-
03-07-2019 - |
Pergunta
Esta questão fornece mais clareza sobre o problema descrito aqui . Eu fiz mais algumas investigações e descobriu que a pilha desenrolar não está acontecendo no seguinte trecho de código:
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");
}
Eu compilei este código usando o compilador VC6 SP5 ea saída é "Wrapper construtor :: AddRef !!!" (Ou seja, o destruidor de objeto wrapper que foi construído na pilha não é chamado. Esse é o comportamento esperado? Ou é um bug com o compilador VC? Posso usar algumas opções de compilação para que o desenrolamento pilha acontece nesse caso?
Solução
Se você quiser usar SEH, você deve usar _set_se_translator função e / opção de compilador EHa.
Outras dicas
padrão A C ++ não dá nada para o trabalho com em caso de comportamento indefinido. Mesmo MS faz. Isso é uma coisa plataforma específica - por isso tome cuidado. Alguns desses flutuantes exceções de ponto estão voltados para exceções Win32 que você pode tentar pegar com _set_se_translator()
. O problema é que você pode capturar exceções Win32, mas, em seguida, sua pilha não será desenrolado corretamente. Pelo menos isso não é algo que você pode apostar sua vida. Onde reside a futilidade do exercício.
Update: A exceção é lançada intencionalmente para verificar o desenrolar pilha. A questão é por destruidor da classe Wrapper não está sendo chamado. - Naveen
Se este for o caso - não fazê-lo. Há maneiras melhores para lançar exceções do que via um comportamento indefinido.
por exemplo:
void OnRecvBuffer()
{
try
{
Wrapper a("AddRef");
throw 42; // this'll throw an exception without invoking UB
}
catch(...)
{
notifyError();
}
}
Você não pode excluir a referência um ponteiro NULL. Você está invocando um comportamento indefinido aqui:
One* p = NULL;
p->x = 10;
Depois que a linha todas as apostas estão fora e você pode ter nos matado todos;)
p
é um ponteiro para um objeto One
. Ele deve conter o endereço de um objeto One
. Você inicializado para 0 - não há nenhum objeto no endereço 0. 0 não é um endereço válido para qualquer objeto (isto é guranteed pelo padrão)
Porque exceção regulares C ++ não lidar com este tipo de exceção, você tem que usar SEH que não sabe nada sobre o aplicativo e não relaxar.
Este é um comportamento indefinido:
One* p = NULL;
p->x = 10;
Neste ponto, o aplicativo é gratuito para falhar sem desenrolar a pilha.
Se você quiser testar a pilha desenrolar substituir este com:
throw 42; // Life the Universe and Everything thrown away
Você não deve alocar dinamicamente todos os seus objcts este é C ++ não Java!
int main()
{
Test pTest; // Note the lack of new!
pTest.OnRecvBuffer();
OutputDebugString("Test");
}