Can you throw exceptions from destructor
Do the benefits of exceptions show up with tiny programs? How do exceptions simplify my function return type and parameter types? Do exceptions separate the "happy path" from the "bad path"? Okay, so you're saying exception handling is easy and simple, right? Mindset and discipline for exception handling? I have too many try blocks; what can I do about it?
How can I handle a constructor that fails? How should I handle resources if my constructors may throw exceptions? How to prevent memory leaks when exceptions are thrown? If a match is found, the control flow jumps to the matching catch block. As the control flow moves up the call stack, destructors are invoked for all objects with automatic storage duration that are constructed, but not yet destroyed, since the corresponding try-block was entered, in reverse order of completion of their constructors.
If an exception is thrown from a destructor of a local variable or of a temporary used in a return statement, the destructor for the object returned from the function is also invoked. Variant members of union-like classes are only destroyed in the case of unwinding from constructor, and if the active member changed between initialization and destruction, the behavior is undefined.
If the exception is thrown from a constructor that is invoked by a new-expression , the matching deallocation function is called, if available. If any function that is called directly by the stack unwinding mechanism, after initialization of the exception object and before the start of the exception handler, exits with an exception, std::terminate is called. Such functions include destructors of objects with automatic storage duration whose scopes are exited, and the copy constructor of the exception object that is called if not elided to initialize catch-by-value arguments.
If an exception is thrown and not caught, including exceptions that escape the initial function of std::thread , the main function, and the constructor or destructor of any static or thread-local objects, then std::terminate is called. It is implementation-defined whether any stack unwinding takes place for uncaught exceptions.
When rethrowing exceptions, the second form must be used to avoid object slicing in the typical case where exception objects use inheritance:. The throw-expression is classified as prvalue expression of type void. Like any other expression, it may be a sub-expression in another expression, most commonly in the conditional operator :. Create account Log in. Namespaces Page Discussion. Views View Edit History.
From cppreference. Keywords Escape sequences. Namespace declaration. Namespace aliases. Fundamental types Enumeration types Function types. Compound types Union types. Default initialization Value initialization Zero initialization Copy initialization Direct initialization.
Expressions Value categories Order of evaluation. Operators Operator precedence. Class declaration Constructors this pointer. Access specifiers friend specifier. One other important thing to be remembered about catch clauses in function-try-blocks in destructors and constructors too is that, unlike in any other catch clause, they do not allow you to stop the stack unwinding.
You can do some operations, modify an exception you caught, re-throw it, throw a different one, but you cannot exit the destructor normally. For an another example of such invisible destructor, consider a function call wrapper described here. The idea, in short, is that we want a wrapper class template Wrap for any type T that for every call to any member function T::f will call B just before f is executed, and will call A just after f is executed.
This makes sense if you want B to be a lock and A to be the unlock on a given mutex. Such wrapper is implementable but requires calling A in the destructor of an auxiliary object whose life time terminates at the end of instruction. Every no-throwing rules that apply to destructors, and best practices you wish to apply to destructors, apply equally to those and similar libraries that utilize destructors in clever ways.
Also note that destructors of temporary objects are scheduled to be run after the full expression they were created in is executed. This might create surprising effects. Consider the following code. Even though the assertion evaluates to true at compile-time, the expression below may still throw an exception at run-time; because the expression creates three temporaries, execution of destructors of those temporaries is not checked in the assertion, and any of these destructors could throw unless they are declared as noexcept.
In order to prevent that, you need to either explicitly declare your destructor as noexcept false or derive from a user-defined type with noexcept false -destructor or have a non-static data member of user-defined type with noexcept false -destructor.
This means that if you used to throw from destructors inadvertently, you will be now calling std::terminate inadvertently. Throw from destructor inadvertently? Do you use a log in your application? Do you log destruction of objects, like this? Even if your logging library swallows all failures logging may fail after all , does LOG take its arguments by value or by reference? A Reference to type std::string?
If you log, do you try to wrap the logging with a catch-all handler that will swallow an exception? This is the case for std::thread. If you create an automatic object of class std::thread in order to launch an asynchronous computation, and you leave the scope trigger the destructor call without having joined with or detached from the other thread, std::terminate will be called. Note that even if your intention is to join with the other thread it might be prevented by an exception throw.
Therefore, the advice for you regarding threads is, do not use such low-level abstraction as thread — really. Use std::async instead:. Excellent post! Thank you! The section Function-try-blocks is not completely true. Indeed, and now I also noticed that at the time of reaching the handler, the member sub-objects have definitely been destroyed.
Thanks for pointing this out! Interesting morning reading. Thus stack allocated objects can still throw from their destructors dribeas wrote above about consequences. Hi Dimitry. The Standard also defines a similar requirement for destructors, although in a two-step manner:. An implicitly declared special member function shall have an exception-specification. A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration.
Pingback: Missing destructor in Visual Studio?
0コメント