Очистка данных после исключения на конструкторе класса

Почему этот код не вызывает CloseHandles в деструкторе класса?
В моем тесте кода я вызываю ‘((MyClass *) pThis) -> CloseHandles ();’ явно, но переменная m_bFinished имеет неправильное значение. Зачем ?

#включают <windows.h>
#включают <исключение>

класс MyClass
{
общественности:

явный MyClass (void ** pThis)
{
* pThis = this;
m_bFinished = false;

// код открытого дескриптора здесь

// происходит ошибка
бросить новый std :: exception ("Исключение брошено!");
}

~ MyClass ()
{
if (! m_bFinished) CloseHandles ();
}

void CloseHandles ()
{
if (m_bFinished) возврат;

// закрываем здесь дескрипторы.

m_bFinished = true;
}

частный:
bool m_bFinished;
};

int main (int argc, char * argv [])
{
MyClass * pMyClass;
void * pThis = NULL;

пытаться
{
pMyClass = новый MyClass (&pThis);
}
поймать (std :: исключение * e)
{
// удалить pThis;

если (pThis)
{
((MyClass *) pThis) ->CloseHandles ();
}
}

вернуть 0;
}

0

Решение

Поскольку деструктор класса не запускается, когда его конструктор выдает — объект еще не полностью инициализирован.

Кроме того, вы на самом деле не бросали std::exception, но указатель на это:

// dynamically allocates std::exception and throws a pointer to it
throw new std::exception("Exception thrown!");

РЕДАКТИРОВАТЬ: Я заметил, что вы ловите указатель тоже, так что это не проблема. Но нет конструктора std::exception это принимает строковый литерал, поэтому мне интересно, как ваш код даже компилируется.

В любом случае, если конструктор может выбросить после того, как сырой ресурс был выделен, у вас есть потенциальная утечка.

Вам нужно обернуть ресурс в классе, который им управляет — возможно, умный указатель или подобное RAII обертка. И использовать списки инициализаторов членов!

Другой вариант — делегирование конструктора (новое в C ++ 11). Объект считается полностью построенным, когда любой его конструкторы заканчивает выполнение. Это означает, что если исключение выдается из конструктора, который делегирован другому конструктору (где вы должны получить дескрипторы), деструктор будут называться.

Для иллюстрации с некоторым кодом:

struct Handle {
Handle() : handle(new int()) {}
~Handle() { delete handle; }
int* handle;
};

class MyClass {
Handle h;
MyFlass() : h() // handle initialized here
{
/**** code that may throw ****/
// this will properly close handles because
// the destructors of already initialized
// members (like h) will be called
}
~MyClass() { /* not called if constructor throws */ }
};

И пример делегирования конструктора:

#include <iostream>

class MyClass {
private:
int* handle;
MyClass(int)  // dummy parameter just for overloading
: handle(new int()) { /* better not throw from here */ }
public:
MyClass() : MyClass(0) // handle initialized here
{
/**** code that may throw ****/
throw 42;
}
~MyClass() { delete handle; std::cout << "dtor!"; }
};

int main()
{
try { MyClass m; } catch (int) {};
}

Выход dtor!,

3

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

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

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