views:

748

answers:

9

I have some C++ code that uses a very standard exception pattern:

try {
  // some code that throws a std::exception
}
catch (std::exception &e) {
  // handle the exception
}

The problem is that the exceptions are not being caught and I cannot figure out why.

The code compiles to a static library in OS X (via Xcode). The library is linked into a Cocoa application, with a call to the function in question happening via an Objective-C++ thunk. I suspect that the interplay between Objective-C and C++ is the culprit but all my attempts to pin this down have failed.

I have not been able to create a simple example that reproduces this behavior in a simple example. When I take the relevant code out of the context of my big program everything works.

Can anyone suggest why my exceptions are not being caught?

+11  A: 

Try a catch(...) {} block, see if an exception is really thrown.

Michael Foukarakis
+2  A: 

I can offer two theories:

  1. the exception gets caught before it comes your catch clause; any function on the stack might be the culprit. As Michael proposes, try catching everything.
  2. exception unwinding fails to locate your handler. To analyze this in more detail, you would have to step through the exception unwinding code, which is very hairy. See whether compiling the Objective-C code with -fobjc-exceptions helps.
Martin v. Löwis
A: 
 try{
      if(true)
        throw exception();

    }catch(exception &e)
    {

    }
adatapost
+1  A: 

This might be a long shot, but in Visual Studio's compiler settings there is an option to switch off exceptions entirely. Perhaps there's something similar in GCC / XCode.

Adrian Grigore
A: 

C++ exceptions can be just about anything, quite frequently a char*. As suggested before add catch (...) to at least get it to break and see what's going on.

Igor Zevaka
A: 

I suspect that the interplay between Objective-C and C++ is the culprit but all my attempts to pin this down have failed.

You're probably right, although it's hard to track down.

First, GCC explicitly does not allow you to throw exceptions in Objective C++ and catch them in C++ ("when used from Objective-C++, the Objective-C exception model does not interoperate with C++ exceptions at this time. This means you cannot @throw an exception from Objective-C and catch it in C++, or vice versa (i.e., throw ... @catch).")

However, I think you're describing a case where Objective C++ calls C++ code, the C++ code throws and you're hoping for C++ code to catch the exception. Unfortunately I'm having difficulty finding documentation for this specific case. There is some hope because, "It is believed to be safe to throw a C++ exception from one file through another file compiled for the Java exception model, or vice versa, but there may be bugs in this area." If they can do it for Java, there is a chance they can do it for Objective C++.

At the very least, you'll need to specify -fexceptions at compile time ("you may need to enable this option when compiling C code that needs to interoperate properly with exception handlers written in C++"). Again, that doesn't specifically mention Objective C++ but it may apply.

Max Lybbert
+3  A: 

One little known gotcha with exceptions relates to the access of the base class.

If you are actually throwing a class that derives privately from std::exception then the std::exception handler will not be chosen.

For example:

#include <iostream>

class A { };
class B : private A { } ;

int main ()
{
  try
  {
    throw B ();
  }
  catch (A & )
  {
    std::cout << "Caught an 'A'" << std::endl;
  }
  catch (B & )
  {
    std::cout << "Caught an 'B'" << std::endl;
  }
}

Usually, such an order of handlers would result in the 'B' handler never being selected, but in this case 'B' dervies from 'A' privately and so the catch handler for type 'A' is not considered.

Richard Corden
+3  A: 

C++ allows you a variety of options for catching: value, reference or pointer. Note that this code only catches std::exceptions passed by reference:

try {
  // some code that throws a std::exception
}
catch (std::exception &e) {
  // handle the exception
}

It's more likely that the exception is being passed by pointer or by value:

catch (std::exception e)
// or
catch (std::exception* e)

Check the code that is throwing the exception, and see how it's doing it.

Bill
Thank you - this just fixed my problem.
Ben L
Glad to hear it, Ben L!
Bill
A: 

Thanks for the input from everyone. Those are good suggestions for anyone who runs into a similar problem. It's working now, but I'm not 100% sure which of various changes I made caused things to become sane again. Once again, the approach of simplifying down to something that works and building back up from there paid off.

One thing that wasn't mentioned in the responses, and which I think was part of my confusion, is to make sure that the handler makes it obvious that it actually caught the exception. I think that in some of my formulations of the handler it was masking that fact and passing the exception on to a higher level handler.

gauss256