Это своего рода продолжение Почему Александреску не может использовать std :: uncaught_exception () для реализации SCOPE_FAIL в ScopeGuard11?
Я хотел бы обнаружить, если кто-то создает MyClass
в деструкторе другого класса (или с активным деструктором где-то в стеке вызовов).
class MyClass
{
public:
MyClass(){
assert(???what to put here????);
}
}
void f(){
MyClass m; //whether this asserts should be context dependant
}
class OtherClass{
~OtherClass(){
MyClass m; //this should assert
f(); //this should too;
}
}
int main()
{
MyClass m; //this should not assert
f(); //this should also not assert
}
Одна попытка может быть:
assert(!std::uncaught_exception());
но это будет работать только в том случае, если деструктор вызывается из-за исключения, а не в том случае, если он вызывается из-за того, что объект вышел из области видимости.
Вы не можете обнаружить это, и вы не хотите. это не бизнес вашего класса. если кто-то позвонит вам из деструктора noexcept, он поймает исключения
Вы не сможете определить, как вызывается ваша функция, если вы не заставите звонящих предоставить эту информацию.
Кроме того, насколько я помню, Visual C ++ никогда не реализовывался std::uncaught_exception
, так что это было бы плохо (для переносимого кода), даже если было известно, что никакой деструктор не вызывал try
блок.
Тем не менее, тривиально определить, вышла ли область из-за исключения или нет.
Просто поместите эту область в try
-блок; вот для чего это.
Например,
class Transaction
{
private:
bool failed_;
Transaction( Transaction const& ); // deleted
Transaction& operator=( Transaction const& ); // deleted
public:
void fail() { failed_ = true; }
void commit() { ... }
// More functionality, then
~Transaction()
{
if( failed_ ) { rollback(); }
}
Transaction(): failed_( false ) {}
};
void foo()
{
Transaction transaction;
try
{
// blah blah
}
catch( ... )
{
transaction.fail();
throw;
}
}
Отказ от ответственности: я не использовал этот шаблон, поэтому не могу подтвердить, насколько это практично.