C ++ Custom Exceptions: Runtime and Exception Passing from C ++ to C (as information on the error)

I am writing a custom C ++ exception class (so I can pass C ++ exceptions to another language via the C API).

My initial plan of attack was as follows:

//C++ 
myClass
{
public:
   myClass();
   ~myClass();

   void foo() // throws myException
   int foo(const int i, const bool b) // throws myException
} * myClassPtr;


// C API
#ifdef __cplusplus
extern "C" {
#endif

myClassPtr MyClass_New();
void MyClass_Destroy(myClassPtr p);
void MyClass_Foo(myClassPtr p);
int  MyClass_FooBar(myClassPtr p, int i, bool b);

#ifdef __cplusplus
};
#endif

      

I need a way to skip exceptions being thrown to the C ++ side of the C side. The information I want to pass to the C side is as follows:

(and). What are (B). where (C). Simple stack trace (only a sequence of error messages in the order they occurred, no debugging information, etc.)

I want to modify my C API so that the API functions expose a pointer to a struct ExceptionInfo that will contain information about the exception (if an exception had been thrown) before using the call results.

So, a C ++ method exposed in the C API would be implemented something like this:

// I have to admit that there is something quirky "hacking" about this kind of implementation (aside from the nightmare) - should there be a better way?

// ExceptionInfo default ctor initialized to no error

void MyClass::foobarTrappedExceptionWrapper(ExceptionInfo& ei)
{    
    try {
      // call foobar ...
      foobar();
    }
    catch(fast_exception& fe)
    {
       switch (fe.errcode())
       {
          //package exception info into ei for C consumption 
       }
    }
    catch(std::exception &e)
    {    
      //package exception info into ei for C consumption 
    }
}

      

The implementation of each of the C ++ methods exposed in the C API must be wrapped in a try / catch statement (see snippet above). The performance implications for this seem to be pretty serious (according to this article ):

"It is a bug (with a high run-time cost) to use C ++ exception handling for events that occur frequently, or for events that are handled near the point of detection."

At the same time, I remember reading somewhere in the C ++ days that everything, although exception handling is expensive, it only gets expensive when an exception actually happens. So which is correct? what to do?. Is there an alternative way that I can safely catch errors and pass the resulting error information to the C API ?. Or is it a minor consideration (the article is pretty old after all, and the hardware has improved a bit since then).

[change]

Removed question2 as I found a way to create a simple stack trace here .

+2


a source to share


1 answer


Answers

  •  
  • Both are correct; you are misinterpreting the first source. The try {} block is cost-free; it's a toss .... a catch (i.e. a spread) that's expensive. So it is cheap if no exception is thrown, so they shouldn't be used if they happen often (because then you throw ... catch often).  
  • Using a very long but fixed size buffer is no less weighty than using std :: string. Using std :: string is a bad idea only if you are concerned that you might throw an out-of-memory exception (in which case the std :: string constructor will throw because it cannot allocate space). But why reinvent the wheel? I suggest you take a look at boost :: exception , which provides a boost :: exception class that allows you to attach arbitrary metadata to the exception object, and it can be lightweight (no metadata) or heavy weight as you want, depending on which the metadata you are using.

A comment about passing C ++ exceptions around C
Choosing to inherit or not inherit from std :: exception does not affect performance; the article mentions the fact that propagating an exception and performing stack unwinding is expensive (regardless of the type of exception). As for passing an exception in the C world .... Passing error in C is usually done using integer return types and error codes, although if you want to pass a C ++ object as well, then if you can copy the type of the exception polymorphically, then you can just create a copy on the heap and then pass the exception object as type void * , and if you need to extract information from that object, then you can create C interfaces implemented in C ++ and which return a void * objectback to a pointer to your exception type and retrieve the appropriate fields. An alternative, if all you want is that the () message is to pass around strdup () the message. Be aware that anything that requires allocation / copying will not work if std :: bad_alloc is one of your handling exceptions (in other words, if you can get out of memory pressure, allocating more memory is not a good idea ).



As the saying goes, "When in Rome, do what the Romans do" ... my own advice would be to use return status codes and error codes in C and use exception handling in C ++. I really wouldn't try to bring the C ++ exception object into the C world. Also keep in mind that more often than not C ++ code calls C code than C code to call C ++ code. If you create C interfaces for your C ++ code, then they should probably behave like C interfaces, namely, return error status codes. If your C ++ code calls a C function that returns an error status code, then it is prudent to throw an exception rather than returning an error status code where the C code failed. In this case, however, you are in the C ++ space and don't have to worry about the exception going into C code. But in case,when you go back to the C world, I would suggest logging all the information you have and using the error status codes.

Also, given that std :: exception :: what () returns a char * object describing what happened, whereas your API returns an integer code indicating the type of the exception ... well, that would really confuse other people using your code. When I saw that you were using waht () in a switch statement, I was about to comment that you cannot include a line, and then I had to do a double trick and realize that it means something different than usual.

+2


a source







All Articles