Multiple active exceptions at once!?



  • So it never occurred to me before that this could happen, or that it was even important for this to be possible; in exception handling, it is possible for multiple active (uncaught) exceptions to exist simultaneously, meaning more exceptions have been thrown than have been caught at this point in time. No, I'm not talking about multithreading - this is within a single thread.

    C++ supports it: http://melpon.org/wandbox/permlink/PscHg988AnzjajyS
    Java supports it: https://ideone.com/ktzmqg
    (I'm too lazy to lookup how exception handling and RAII are done in other languages - I leave that as an exercise to the reader)

    So the rationale is that sometimes during stack unwinding, exceptions are safely thrown and caught. It would be a Bad Thing™ if that normally benign exception handling became troublesome if the reason for the stack unwinding just so happened to be due to another exception. This is all sane and reasonable, but it still made me go :wtf: initially because of how crazy it sounds. (I think that qualifies as Side Bar WTF? If not, oops.)

    More detailed explanations for us C++ programmers:

    Are there any languages with exception handling which don't support this? It seems like it would be an oversight to not allow it, considering the reasonable likelihood of benign exception handling happening during stack unwinding, but it does seem to be an obscure feature. (Of course, not supporting RAII in a language is an even bigger oversight IMO)


  • BINNED

    looks interesting, the only time I think this could happen in a single thread is during a constructor. And in C++ throwing an exception in constructors is a wacky business (yet it is still common in certain places). C++ is a shitty language only perhaps better than Java anyways.



  • The standard file stream destructors swallow exceptions thrown by close(), so it's not uncommon at all.


  • BINNED

    Yes as I said it is common, this is a bug in the language itself. However, when you start to see the need to these obscure corners of C++ it is time to re-think the decision to stick to C++. If there is already a big code base in C++ that is prohibitive to re-do it in a sane language, at least one should use boost or Qt and assume language is called boost/Qt.



  • Um, what? Java supports it too, for good reason. It's not a bug in the language, it would be a bug if it wasn't supported.


  • Winner of the 2016 Presidential Election

    @dse said:

    And in C++ throwing an exception in constructors is a wacky business

    Umm... No. Last time I checked, throwing exceptions from constructors was perfectly ok and, in fact, the only sane way to signal failure conditions during object construction.


  • sockdevs

    .NET supports it too, for the same reasons I guess; I would have had an ideone link to show it, but there was a server error, and I lost the code :cry:


  • Winner of the 2016 Presidential Election

    @dse said:

    when you start to see the need to these obscure corners of C++

    Ok, we get it: You hate C++. I do as well, and I use it regularly. But you're very wrong here. If you think this is one of the obscure corners of C++, you don't know enough about C++ to be entitled to bitch about the language. This is, in fact, one of the things that C++ got right.


  • BINNED

    If you see your constructor has become this monstrosity that is trying to make a socket connection to authenticate, and you end up with language constructs that deservedly show up in SBWTF perhaps there is something wrong. It is part of the language, and is a necessary workaround to have RAII, but boost developers have done a better job for us to use it. It means this a design implementation leaked into the language, not anyone but boost or Qt developers should need to see it.



  • Please don't start a language war, especially over my favorite language.


  • BINNED

    It is necessary, yes but just a workaround for a bug in a doubly-glorified assembly language.

    @LB_ said:

    Please don't start a language war, especially over my favorite language.

    sorry, my last rant.


  • Winner of the 2016 Presidential Election

    @dse said:

    It is necessary, yes but just a workaround for a bug in a doubly-glorified assembly language.

    Sorry, bud, but I'm convinced that you have no fucking clue what you're talking about. You like boost and you think RAII, the best feature that C++ has to offer, is a hack. You cannot possibly have any experience with modern C++.


  • sockdevs

    @dse said:

    It is necessary, yes but just a workaround for a bug in a doubly-glorified assembly language.

    So you'd rather have two-step initialisation? Or maybe you like partially constructed instances?

    And it's not just C++ that has RAII; a lot of OO languages have that as a feature.


  • Winner of the 2016 Presidential Election

    @RaceProUK said:

    So you'd rather have two-step initialisation?

    Maybe he works at Google.


  • Winner of the 2016 Presidential Election

    @RaceProUK said:

    And it's not just C++ that has RAII; a lot of OO languages have that as a feature.

    No, I'd actually argue that most languages don't. Try-with is not a replacement for destructors, not at all. Just think about cases where you need to have a factory method that allocates resources. This is a fucking mess in any language that doesn't have destructors if you want to write exception-safe code, because you have to litter your code with a lot of trys and finallys in many places. In C++, it's a no-brainer if you design your classes correctly.


  • BINNED

    RAII is the only sane way (specially in C++), I did not say anything against it!
    But do you have to count how many times uncaught exceptions were thrown to make it happen? not just that an exception happened but how many times!! If you did not see the specs here look again, it has been bool till C++17 but now it is an int, yes this is a hack!



  • std::uncaught_exceptions is provided simply for completion sake, not because it is actually needed. In fact its use is discouraged in one of the links in my OP...


  • Winner of the 2016 Presidential Election

    @dse said:

    But do you have to count how many times uncaught exceptions were thrown to make it happen?

    Well, this standard library function is totally useless and 99.99999% of all C++ programmers should never use it. And you don't need to use it, ever. See the OP.

    Crap ... :hanzo:d


  • sockdevs

    @asdf said:

    No, I'd actually argue that most languages don't. Try-with is not a replacement for destructors, not at all.

    True, but you have to remember that in managed languages like Java and C#, you don't necessarily know when destructors will run, as they're called by the garbage collector. It's a big enough issue that for C#, it's recommended to write finalizers instead. But even that's not enough, because again they're called by the GC; the only predictable way to do it is by implementing IDisposable and wrapping the usage in a using block. OK, it may not fit the strict definition of RAII, but it serves the same purpose.


  • Winner of the 2016 Presidential Election

    That's exactly why I don't like garbage collection. ;) I can't count how many times I wished Java would have reliable destructors.



  • This is why I stick to C++: deterministic destructors. I always know when the code I write will run, no weird GC semantics that I have to study and profile. GC works well in some situations but never in the situations I end up in.


  • sockdevs

    @dse said:

    But do you have to count how many times uncaught exceptions were thrown to make it happen?

    Yes, in the same way you have to perform rectal surgery in the end zone of a handegg field.


  • BINNED

    @LB_ said:

    std::uncaught_exceptions is provided simply for completion sake, not because it is actually needed. In fact its use is discouraged in one of the links in my OP...

    And this is exactly what workarounds for bugs look like.


  • sockdevs

    @LB_ said:

    I always know when the code I write will run, no weird GC semantics that I have to study and profile.

    There's a reason it's recommended to never write destructors in C#, and instead use IDisposable ;)


  • sockdevs

    @dse said:

    And this is exactly what workarounds for bugs look like.

    OK, you obviously have either a vendetta or no clue what you're on about.

    I'm willing to bet a bit of both.


  • Winner of the 2016 Presidential Election

    @dse said:

    And this is exactly what workarounds for bugs look like.

    Stop embarrassing yourself. It has become clear by now that you have no fucking clue what's actually good and bad about C++ and yet you keep insisting that the existence of a nonsensical library function proves the existence of some kind of bug.



  • Slap fight!


  • Winner of the 2016 Presidential Election

    @RaceProUK said:

    Yes, in the same way you have to perform rectal surgery in the end zone of a handegg field.

    I literally lol'ed. Bookmarked for future reference :D


  • Winner of the 2016 Presidential Election

    You can take over now. I'm done here.



  • Sorry everyone, maybe I should have added a trigger warning? I didn't think of it at the time because this isn't exclusive to C++.


  • sockdevs

    @LB_ said:

    I should have added a trigger warningbaited fishing rod emoji

    Because you're almost guaranteed to hook that one idiot who claims to know better than people who design programming languages for a living, and have been doing so for decades.


  • BINNED

    Clearly you know this subject matter better, so I leave that to you experts.


  • sockdevs

    That is the most intelligent thing you've said in this whole topic





  • Probably a better example: https://play.golang.org/p/449fho1p-k


  • Discourse touched me in a no-no place

    @LB_ said:

    This is all sane and reasonable, but it still made me go :wtf: initially because of how crazy it sounds.

    The alternative would be to enforce that all functions called during any part of exception handling are exception-free. From a language design perspective, that's massively intrusive and a definite WTF. From a language user perspective, that'd be super-annoying! (Enforcement of a guarantee != generate a warning if you detect it.)

    The only awkward bit comes if a secondary exception escapes upwards past the point where the primary exception would become the active one again. At that point, you need to do exception chaining so that you record that the secondary one was caused by the first or you'll lose track of what the original exception was entirely (which would make debugging insanely difficult). This sort of consideration is why there should be a superclass of all exceptions so that there's always the ability to handle these things. Java almost gets this right (it doesn't enforce stitching of the exceptions together) and C++ doesn't (it doesn't enforce a common superclass in the first place). Don't know about C#.

    It's still a bit of a language-wonk thing. :smile:


  • sockdevs

    C# (and .NET as a whole) has the single superclass Exception, but I don't think it forces stitching them together


  • Discourse touched me in a no-no place

    That's very much like how Java works. It allows you to get things right with good coding habits, but poor programmers can still Belgium everything right up.



  • AFAIK you can do this with std::exception_ptr, which can hold any type of exception (regardless of type). You still need a way to store the the exception_ptr in your exception type, so it's not a complete solution, though.

    Boost.Exception is helpful here, as you can attach additional information to your exceptions on the fly (again, largely independent of their actual type). For nested exceptions there's errinfo_nested_exception.


  • Discourse touched me in a no-no place

    @LB_ said:

    Sorry everyone, maybe I should have added a trigger warning? I didn't think of it at the time because this isn't exclusive to C++.

    Yes, anything involving C++ needs a trigger warning. :trollface:



  • C++ has standard library support for nested exceptions now:



  • An error occurred while retrieving this page. Additionally, an error occurred while retrieving the error page for that error.

    ^- real life example of exception needing an exception. You've probably seen it a hundred times on the webs.



  • Huh, managed to miss that one.


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.