views:

143

answers:

5

We all know that throwing pointers to exception is bad:

try
{
    ...
    throw new MyExceptionClass();
}
catch (MyExceptionClass* e)
{
    ...
}

What's your approach to cleaning the catch targets up in legacy code? I figure that I can fix the first part by making operator new private:

class MyExceptionClass
{
public:
    ...
private:
    void* operator new(size_t);
}

How can I make the catch side of things equally ugly at compile-time? I don't want to just cause this to fall into the catch (...) territory.

A: 
Tobias
A: 

As far as in C++ language rules, you can't disallow pointers to a type which makes catching pointers to them completely legal (however ugly). I would write a simple tool which would look for all the catch(T*) blocks and just change those.

I'd say making operator new private might not work because the global new operator might still be invoked. What I'd suggest for legacy code bases to force breakage of dynamic allocations would be to change the signature of the constructor of the MyExceptionClass -- or add a static assert in the default constructor and force compilation failures so that you can identify where these default-constructed MyExceptionClass types are instantiated.

One other approach I would take would be to look for 'throw new' clauses and just fix those.

Dean Michael
+1  A: 

It sounds like you want to be able to change all instances of throw by pointer to throw by value. You have a workable kludge to prevent throwing by pointer. But you are looking for a way to prevent accidentally catching by pointer once all the throws are changed.

As far as I know this is not able to be enforced by the language. But a simple sed script to look for instances of /catch (.* \*/ should be good enough I would think...

Greg Rogers
Yeah. I was afraid that would be the case. Thanks.
Austin Ziegler
+2  A: 

If I understand you correctly, you want to turn a bad practice into a compilation error.

By making the exception type non-heap-allocatable, you've managed to make this illegal:

throw new MyExceptionClass();

Alas, the next part can't be done like you want it. There's no way to make the catch block illegal. Although, if you've made it illegal to heap-allocate MyExceptionClass, there's no need to worry about the catch blocks. It'll just be wasted space.

If you want to enforce not catching by a pointer, you want a lint-like tool. I'd recommend looking at EDoC++. It's a modified gcc compiler to check for proper exception usage.

Tim
+2  A: 

There is nothing you can do to prevent catching by pointer, aside from static analysis tools or code review. However, if you make it nearly impossible to throw a MyExceptionClass pointer, a catch(MyExceptionClass*) block will be dead code.

To more completely prevent throwing by pointer, you'll actually need to do some more work.

Hide all forms of operator new -- See here.

Hide the address-of operator -- Throwing the address of a previously allocated object carries some of the same issues of throwing a heap-allocated object.

class MyExceptionClass
{
private:
    MyExceptionClass* operator&();
}
Patrick Johnmeyer
Excellent point; I hadn't thought of the address-of operator.
Austin Ziegler