Деструкторы не выполняются (без разматывания стека) при возникновении исключения

Я обнаружил очень и очень странное поведение, которого никогда не видел прежде.
Я работаю над сложным проектом VS2005 C ++.

class Tester
{
public:
Tester()
{
TRACE("Construct Tester");
}
~Tester()
{
TRACE("~Destruct Tester");
}
};

void Thrower()
{
Tester X;
throw std::exception("Booom");
}

Что вы ожидаете увидеть в выводе трассировки, когда Thrower() называется?
Этот тестер создается, а затем разрушается, когда стек не разматывается, или нет?

По крайней мере, я ожидаю этого, но деструктор Tester никогда не называется!

Невозможно !?!?!?!

Это ошибка в Visual Studio?

Я много искал, но даже не в Stackoverflow я нашел ответ.

1

Решение

Мне потребовался целый день, чтобы выяснить, в чем дело.

Теперь я должен немного глубже объяснить, что я делаю.
У меня есть код C ++, который компилируется в файл LIB. Код выше (Tester and Thrower) находится в этом простом файле C ++ LIB.

И у меня есть другой код C ++, который компилируется в управляемую DLL C ++, которая связана с этим файлом LIB. Таким образом, в конце оба кода находятся в одной и той же DLL. Я управлял функциями-обертками, которые вызывают код в файле LIB следующим образом:

ManagedWrapper()
{
try
{
Thrower();
}
catch (std::exception& e)
{
throw new System::Exception(e.what());
}
}

Это делает НЕ Работа.
С этим кодом у меня есть утечки памяти и сетевые сокеты, которые не закрыты.
Стек в Thrower не разматывается.

Причина этого заключается в том, что разматывание стека не происходит до того, как будет достигнут улов. Но когда catch сидит в другой библиотеке, чем throw, стек не разматывается. DLL не знает, как развернуть стек в файле LIB (хотя оба они, наконец, скомпилированы в одну и ту же DLL !!)

Но я нашел чрезвычайно простое решение.

В файле LIB мне нужно было добавить промежуточную функцию между ManagedWrapper () и Thrower () следующим образом. Код выглядит глупо, но он решает проблему:

Catcher()
{
try
{
Thrower();
}
catch(...) // unwind HERE
{
throw;
}
}

Важно то, что этот перехватчик должен находиться в LIB-файле, где выдается исключение. Когда исключение перехвачено, стек разматывается, а затем исключение повторно отправляется в управляемую оболочку.

Иногда код, который выглядит глупо, очень умный!

РЕЗЮМЕНикогда не забывайте, что исключение всегда должно быть перехвачено в той же библиотеке, в которую оно было брошено. Если они попадают через границы библиотеки, у вас серьезные проблемы.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]