C++ Zombie flag altneratives

Started by
34 comments, last by SiCrane 14 years, 9 months ago
Quote:Original post by SneftelHmm... Offhand, I'd guess that it is impossible for a tail-recursive function to become non-tail-recursive as a result of anything related to exceptions. Got an example?


Imagine a recursive function that instantiates class A near the beginning (but after the noop check), and destroys it again right before the recursive call. A good compiler should be able to work out that A is always destroyed before the next level is called, so all instances of A can be collapsed down to a single hunk of storage (like any other variable in a tail-recurse case.) It doesn't have to plant any stack frame code and is free to generate a loop. And best of all, it may be able to optimize the constructor and destructor of A into a single "(re)init A" code block, depending on what they do. These are small wins individually, but taken together you get somewhere.

But if any point in the function can throw an exception, due to some calls it makes, the compiler is going to have to choose between planting code to remember when A needs to be deconstructed, or just using stack frames and deconstructors normally. The latter is likely to be simpler, compilers are already good at that. A brilliant optimizer might do well here, but such brilliance is not common.

I saw that behaviour out of (if failing memory serves; I've used a lot of compilers over the years) gcc on Solaris a number of years ago, and I got around it by recoding for iteration manually, and some refactoring. It was a rare case, but it stuck with me. Bookkeeping costs space or time, usually both. Exceptions require bookkeeping.

Quote:Blame C++'s milquetoasty exception specifiers.


I do. I don't object to exceptions in Java (in fact, it's hard to imagine Java without them.)

Quote:
Quote:It leads people to think of the error handling as a sort of afterthought
How so?


I've seen this done in commercial code: "Damn, we've got a bug and it's crashing the server. And we have to release. Just put a catch(...) near the beginning and we'll call it fixed."

I was called in to review the code, and I hit the ceiling. First of all the code was supposed to be portable, and using ... to handle bad pointers is not portable. Secondly, the whole mentality of "if we screw up, exception handling will save us" told me we had an education problem. Management didn't see the problem - the crash had been fixed, right? But this server dealt with personal information, and evidence of memory problems in the code was a nightmare scenario to anyone with an actual conscience.

I looked at other code, under new development. The developers who had saved the day with the catch statement had turned proactive - now they were adding catch (...) to all new code, right at the start. Problems? What problems? And they'd gotten fond of throw, as well, but not so fond of smart pointers... Exceptions made all that nasty thinking and checking and worrying about handling error go away. The code looks so much simpler without error paths! And no more crashes! Just some occasional wrong answers that QA didn't always catch! They were productive now!

Those developers were not happy with me - I forced them to stop masking problems and write actual working code. Management was not fond of me: I was Making Scary Noises and causing rework when all they wanted was a lower bug count by yesterday.

I realize that exceptions can be used well. I realize that part of the problem is C++, and they work better in Java. But my experience in the commercial world is that management wants to hire cheap and not hear about problems, and that leads to certain coding styles. So I've learned not to teach styles that lead people into temptation. Especially not now that I work on software with the possibility of mishandled error=human fatality.

Quote:Actually, the runtime cost of the bookkeeping when exceptions are not thrown pretty much IS a free lunch. You should read up on DWARF-2. It's pretty clever how it works.


It is. I look forward to working in an environment where the code (some of it ported to several different platforms) is compiled on systems that are up to date enough to all provide it reliably. Another decade, I figure. In the meantime, for that reason and others, we do not use exceptions in our real-time, safety critical, high speed, portable code.
Advertisement
Quote:Original post by ScottMayommon.

I saw that behaviour out of (if failing memory serves; I've used a lot of compilers over the years) gcc on Solaris a number of years ago, and I got around it by recoding for iteration manually, and some refactoring. It was a rare case, but it stuck with me. Bookkeeping costs space or time, usually both. Exceptions require bookkeeping.


In more recent news: Since 2005, C++ compilers have taken quantum leaps in terms of optimization, spurred by Microsoft's release of standard compliant VC++.

Yes, the old C++ compiler for VAX did consume so many punchcards for exceptions that environmentalists started complaining over dead trees. And this was mere 5-6 years ago.

Things change. A lot.


There are legitimate concerns over exception use and abuse, but can we please lay of this "they are slow" and bloated nonsense.

What is your opinion on polymorphism? Is it also slow, bloats the classes and breaks the cache?
What about templates and meta programming?
What about boost?
about dwarf 2 & performance: well ok, I didn't know that..
is dwarf 2 also available for microsoft compilers or just on gcc ?

Quote:Original post by ScottMayo
If you are using exceptions, you probably aren't doing
Thing* t = new Thing();
because, you're right, you are begging for leaks. What you are probably doing is some variation of
SmartPointer<Thing> t = new Thing();
where SmartPointer<Thing> has a destructor that frees what it points to. Don't think of using exceptions unless you avoid new entirely, or know what smart pointers do. It only leads to grief.


the allocation was just an example, it could be anything, from setting a state in another object,
to creating a sound emitter in the soundsystem, or creating a win32 window.
all of this would be left alone in the dark, because the part between try and throw was not informed about it.
It feels like growing a child and when it dropped out of school, I would dump it and try to raise another.

I guess this is a topic I would have to read a little more updated tutorials & articles about to find out how my problems can be avoided.
My
any links/books on that topic would be very appreciated :)
Quote:Original post by TTK-Bandit
I guess this is a topic I would have to read a little more updated tutorials & articles about to find out how my problems can be avoided.

Scott Meyers' Effective C++, if I recall correctly, has a great description of the difficulties of exception safety and techniques for getting around them.
Quote:Original post by TTK-Bandit
the allocation was just an example, it could be anything, from setting a state in another object,
to creating a sound emitter in the soundsystem, or creating a win32 window.


These are all allocations/acquisitions of one kind or another. Database connections, mutex locks, hardware contexts, file handles... whatever. The same principle can be applied.

Learn about RAII (Google it). It's worth knowing even if you don't use exceptions, especially since languages other than C++ often struggle to provide something similar.

Quote:Original post by TTK-Bandit
I guess this is a topic I would have to read a little more updated tutorials & articles about to find out how my problems can be avoided.


Exceptional C++ (and its sequels).
Quote:Original post by TTK-Bandit
is dwarf 2 also available for microsoft compilers or just on gcc ?

Dwarf2 is pretty much gcc specific. Microsoft's exception handling mechanism is based on SEH. While not free, SEH exception handling is very cheap when exceptions are not thrown. For more complete details see my article here.

edit: grammar

[Edited by - SiCrane on July 25, 2009 2:35:24 PM]

This topic is closed to new replies.

Advertisement