Have an amazing solution built in RAD Studio? Let us know. Looking for discounts? Visit our Special Offers page!
C++CodeHow-To'sNewsRAD StudioWindows

Upgrading C++Builder 12.2: Tip #5, Split out C++ EH and SEH exception handling

Splash image for upgrading to C++Builder 122 Tips Tricks 5 Split C++ and SEH exception handling

Screenshot Radically Different Why C++Builder 122 Matters webinarWelcome to a series of tips and tricks for taking advantage of the new Windows 64-bit Modern toolchain in C++Builder / RAD Studio 12.2! This builds on a webinar we did sharing a bunch of useful information on why and how the new C++Builder matters to you, where this was the very end (so go watch the start!)

Tip #5: Split out C++ EH and SEH exception handling

After three separate variants of tip #4, something completely different!

Exception handling. There are multiple types and mixing them is A Bad Thing. Don’t mix C++ exception handling and SEH exception handling. It’s (a) not safe and (b) won’t work. But even better, we have a tool to help you separate them.

What does this mean?

C++ exceptions are when you throw a C++ object (which can be any type, even an int.) C++ exception handling is try-catch.

Structured Exception Handling (SEH) is not a purely C++ concept, but has extra keywords added to C++ in order to support it. This is the kind of exception raised via the RaiseException() API (ie not throw) or for some hardware or kernel exceptions. You most likely don’t have a SEH handling mechanism (__try-__filter()) but you very likely may be using __try/__finally.

Both these are completely fine to use. In fact, we reworked our SEH significantly in 12.2 and believe it works very well.

The issue is when you mix the two, such as:

This code has a SEH handling mechanism directly inside the C++ EH handling mechanism. You could mix the other way around too. The point is: two EH mechanisms in the same code.

Why is this bad? Codegen. It is almost impossible to support two different types of exception handling in the same “frame” (same method, think of it as a call stack entry), using two control flow mechanisms, two triggers for unwinding objects, etc. (For an example of the kind of craziness, imagine — this isn’t quite it but is close in terms of expressing the craziness of how it could work — having one method that had various returns, but also a bunch of gotos; you could goto inside loops and goto inside other logic structures; then for fun you added other control flow (say, setjmp/longjmp) to mix with gotos, so execution was moving around all over the place using different systems for moving; and then you had to ensure that code was correct, including invoking all scope-exit behaviour like destructors. This may give a sense of the kind of codegen that multiple exception handling and control flow mechanisms can create.) Visual C++ doesn’t support it, and neither do we.

But in the past you could write this code and the compiler would let you do it. Now, it will give you an error. That may appear as though previously working code now doesn’t work, but that’s not the case: it’s very likely the codegen for that old code was horrendously wrong and resulted in exception memory leaks, may have had issues calling destructors in the right order or at all, etc. It’s a case of: wrong, but you may not have known it.

Note: A big theme of C++Builder 12.2 (see all the versions of tip 4) are that the new compiler can make previously dangerous code safer. We’ve used it for this purpose ourselves!

How can I fix it?

Ok, so you might be convinced that mixing two different types of exception handling in the same frame is crazy and asking for trouble, and you should never do it. But you might still have code you need to fix.

You need to split the two kinds of exception handling. Both types of exception handling can live in the same app just fine, and live in the same code path and call stack, just not in the same method. So splitting means: taking the inner part of a try/catch, or __try/finally, block and putting it in a new method.

Let’s take this messy code (adapted for the purposes of demonstration only, please don’t judge me):

Pop quiz: suppose an exception is thrown in the __try block (say, setting the Width property gives an access violation.) What is returned: m_pBitmap.get(), or nullptr?

To clean this up, we want to move the entire __try/__finally pair into its own method.

We have a tool to do this for you: simply select the code, right-click, choose Refactor, and then Extract Method:

Selecting the try finally block right click showing the Refactor > Extract method menuThe result looks like this:

Screenshot of two methods where the second was created using Extract MethodNote that it handles parameters: it will correctly use parameters to pass on local variables, parameters from the first method, etc, also making them const or reference as appropriate. Here they were simple value types that were not modified, so they were const-by-value.

We added this refactoring in C++Builder 12.2 specifically for this use case. Extract Method takes a block of code and pulls it out into a new method. It is smart and will handle variables, create parameters in the extracted method, make them reference if required, etc.

So if you see this compiler error, you know what to do: select the code, Refactor, Extract Method. Then continue on! This once-off maintenance will solve bugs you may not even have known you had, plus, it makes exception handling reliable.

 

 

See What's New in 12.2 Athens See What's New in 12.2 Athens Dev Days of Summer 2-24

Reduce development time and get to market faster with RAD Studio, Delphi, or C++Builder.
Design. Code. Compile. Deploy.
Start Free Trial   Upgrade Today

   Free Delphi Community Edition   Free C++Builder Community Edition

About author

David is an Australian developer, currently living in far-north Europe. He is the senior product manager for C++ at Idera, looking after C++Builder and Visual Assist.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

IN THE ARTICLES