4

So far I never had a single warning emitted by a C++ compilers but now VS 2015 compiler seems to suddenly start complaining about this.

It seems that C++11 implicitly mark every destructor as nothrow https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(C4297)&rd=true

Why is that? It may be a bad idea, but I would like to understand why? And if it's not inherently bad, is there a way to override it so that destructor is not a nothrow?

P.S. I know that exceptions may be evil, but sometimes they are usefull, especially when generating crash reports from users of my app.

Petr
  • 13,747
  • 20
  • 89
  • 144

4 Answers4

6

Destructors are called when scopes are exited. When an exception is thrown, the stack is unwound which causes scopes to be exited and destructors to be called. When an exception is thrown while another is in progress, the process is unconditionally aborted with std::terminate. That is why throwing from destructors is a bad idea and why destructors are implicitly marked noexcept (==noexcept(true))*.

If you want to throw from a destructor anyway, you can explicitly mark it noexcept(false) to override the default.


*If you throw from a function marked noexcept, std::terminate is called immediately

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • Also, few parts of the stdlibrary are exception-safe in the face of throwing destructors... – Deduplicator Nov 07 '16 at 00:16
  • User destructors are not always implicitly marked noexcept - they are only marked noexcept if an implicit destructor would be also - see http://stackoverflow.com/a/32957030/1411457 – harmic Nov 07 '16 at 00:33
2

Why is that? It may be a bad idea, but I would like to understand why? And if it's not inherently bad, is there a way to override it so that destructor is not a nothrow?

Throwing exceptions in a destructor is a bad idea. The reason being during an exception stack unwinding happens i.e. destructor for all the objects on the stack is called. Now, as the stack unwinding was happening as a part of the exception, the destructor throws an exception again. You can end up having multiple exceptions and then there is no un-ambiguous way of handling these multiple exceptions. E.g. if there are two exceptions and I have a catch block for one exception and not other, shall my process terminate or the exception caught and processed further?

Jay Rajput
  • 1,813
  • 17
  • 23
2

The other answers have done a pretty good job of explaining why throwing in a destructor is a really bad idea. Sutter & Alexandrescu explain in C++ Coding Standards (2005) "Destructors, deallocation, and swap never fail", which is another way of saying they have no preconditions. Scott Meyers gives the canonical advice in Effective C++ (3rd Ed.) (2005) "Prevent exceptions from leaving destructors" and in Effective Modern C++ (2014) "Declare functions noexcept if they won't emit exceptions".

Engineering is often about trade-offs and compromises and difficult decisions. Sometimes you might need to throw in a destructor. You better have a damn good reason, and you're probably wrong. In such a case, you can declare the destructor noexcept(false) to override the default. Then you get the C++98 behaviour. And if you want to conditionally throw if the stack is not currently being unwound by another exception, you can use std::uncaught_exception. Handling errors that occur while handling errors is a rabbit hole you would be ill advised to venture down.

If your intent is to capture a snapshot of the state of the program at the moment that the exceptional state is detected, to phone home through Google Breakpad for example, then exceptions are not a good solution for that. The automated stack unwinding will discard useful information about the state of the program. You typically want to preserve the state of the stack in your crash report, which usually means calling std::terminate or std::abort.

Oktalist
  • 14,336
  • 3
  • 43
  • 63
0

Because if exception is thrown before application handle a current exception program will terminate.

Probably I will get many -1 for this but I will say it anyway. You can throw a exception inside destructor. You can also do many more things that most people will say it's "evil" and everything will be ok even more it will work better then without "evil" part. But you need to know exactly what are you doing.

Logman
  • 4,031
  • 1
  • 23
  • 35
  • OK... so what? I don't have a problem with that and this scenario is nearly impossible in my case. If I am not able to throw exceptions and leave the code execute in its exceptional state, it would likely segfault anyway, which is IMHO even worse than throwing an exception. – Petr Nov 06 '16 at 23:32
  • @Petr Then another reason: Bad program design. I can't imagine a reason for exceptions in destructors. Btw., `I know that exceptions may be evil` Not. – deviantfan Nov 06 '16 at 23:34
  • @Petr No you don't get it. Sometimes you don't have control when object will be destroyed and in that case your application will fail. If you writing simple app you can predict most scenarios but for more complex app probably this will blow in your face. – Logman Nov 06 '16 at 23:35
  • @Petr `it would likely segfault` If destroying an object can potentially lead to a segfault then IMO you have a very serious design issue. What you are saying is that you are not sure if you can destroy the object at all. Or worse, you can end up in an inconsistent state with objects partially destroyed. That may work for you now but at some point it probably will backfire at you. And all of that is not because of a bug, but you do it intentionally? – freakish Nov 06 '16 at 23:43
  • BTW Nothing stops you from catching exceptions in destructors and reacting appropriately. But doing that would be useful only when dealing with 3rd party. – freakish Nov 06 '16 at 23:47
  • @freakish yes that is true, but at some point I was using the exception to handle a situation where I get into an exceptional state (in my case unable to open certain fd necessary for proper execution). In this case the application wouldn't be completely safe to continue as undefined behaviour might happen and I wanted to throw an exception which I am handling using google breakpad's similar report form - so I would at least have a nifty error report that contains a very clear reason for failure. Not being able to throw exception means not being able to use this error reporting feature... – Petr Nov 06 '16 at 23:47
  • @Petr I am not sure I understand. Which part of that happens in a destructor? It doesn't sound like it should. I am not familiar with google breakpad. – freakish Nov 06 '16 at 23:50
  • @Logman You can, but you must mark the destructor `noexcept(0)` to override the implicit (dtor-specific) `noexcept(1)` first. Throwing from a `noexcept(1)` function gets you `std::terminate`'d right away. No chance to catch the error. – Petr Skocik Nov 06 '16 at 23:53
  • To future readers @PSkocik was referring to second part of my answer first part that says about exception inside exception is always true and `noexcept(0)` is not turning off this functionality. – Logman Nov 07 '16 at 00:18