Я пытаюсь написать модульный тест, который обнаруживает недопустимое использование функции lock() моего класса. Для этого я хочу использовать деструктор и исключить из него исключение. К сожалению, вместо исключения исключения g ++ решает вызвать std :: terminate().Почему я всегда получаю «завершение вызова после вызова экземпляра ...» при метании моего деструктора?
Существует очень упрощенная версия класса:
class A
{
public:
A() : f_lock(0) {}
~A() { if(f_lock) throw my_exception("still locked"); }
lock() { ++f_lock; }
unlock() { --f_lock; }
private:
int f_lock;
};
Существует действительное испытание:
A *a = new A;
a->lock();
...
a->unlock();
delete a;
Существует инвалиду тест, который я пытаюсь написать:
A *a = new A;
a->lock();
...
bool success = false;
try
{
delete a;
}
catch(my_exception const&)
{
success = true;
}
catch(...)
{
// anything else is a failure
}
if(!success)
{
// test failed...
CPPUNIT_ASSERT(!"test failed");
}
Прямо сейчас, delete
звонит std::terminate()
, хотя бросок не указывается d, когда другое исключение активно. (то есть std::uncaught_exception()
является ложным.) И также я, очевидно, поймаю все исключения!
Я делаю что-то неправильно или g++
запрограммирован так, чтобы это всегда было в деструкторах?
Update:
Ответ на DYP в комментариях ниже работ! Далее непосредственно не называют std::terminate()
:
~A() noexcept(false) { throw ...; }
Также для справки о том, почему вы не хотите, заброс в деструкторе, эта страница отлично;
Для выяснения, есть полная версия деструктора. Как мы видим, я сначала отправляю сообщение (оно обычно входит в вашу консоль, может также идти в журнал). Во-вторых, я уверен, что мы еще не управляем исключением. Наконец, я выбрал исключение exception_exit
, которое, как ожидается, заставит terminate()
, хотя в графическом приложении вам может понадобиться показать сообщение MessageBox, чтобы пользователь знал что-то (так как вы можете захватить сообщение, вы можете отображать это пользователю), а затем принудительно отключить приложение.
Node::~Node() noexcept(false)
{
if(f_lock > 0)
{
// Argh! A throw in a destructor... Yet this is a fatal
// error and it should never ever happen except in our
// unit tests to verify that it does catch such a bug
Message msg(message_level_t::MESSAGE_LEVEL_FATAL, err_code_t::AS_ERR_NOT_ALLOWED);
msg << "a node got deleted while still locked.";
// for security reasons, we do not try to throw another
// exception if the system is already trying to process
// an existing exception
if(std::uncaught_exception())
{
// still we cannot continue...
std::abort();
}
throw exception_exit(1, "a node got deleted while still locked.");
}
}
Кроме того, еще одна деталь, вы должны использовать NodeLock
объект для управления флагом F_LOCK. Это безопасно для исключений, поскольку использует RAII (то есть блокировку с привязкой). Однако в этот момент я не хотел принуждать пользователя использовать NodeLock для блокировки/разблокировки узла, следовательно, этот тест в деструкторе.
Начиная с C++ 11, большинство деструкторов по умолчанию являются 'noexcept'.Попробуйте объявить его как «noexcept (false)» (или, еще лучше, попытайтесь создать свои классы, чтобы не выбрасывать деструктор). – dyp
Мне очень любопытно, чего вы ожидаете. Скажем, вы поймаете исключение - у вас есть объект, который выходит за пределы области действия, но не разрушен. Чем ты занимаешься? –
@ dyp, спасибо за ответ! Это сработало. Извините, я не могу дать вам баллы за это, так как Matt & Jonathan решил, что это дубликат аргумента, почему вы не должны делать то, что я пытаюсь сделать, но НИКАКОЙ ОТВЕТЬТЕ на мой вопрос. Очень раздражает, если вы спросите меня. –