5
\$\begingroup\$

I have some function like:

void foo() { ... }


int main() {
  ...
  try {
    ...
    foo();
    ...
  } catch (const std::exception &e) {
    std::cout << "Fatal error: e.what() << std::endl();
    return;
  }
  ...
}

If an exception is thrown from foo, I'd like to know it. Also I want to know the reason of the original exception. I can split the code like this:

int main() {
  ... 
  try {
    ... 
  } catch (const std::exception &e) {
    std::cout << "Fatal error: " << e.what() << std::endl;
    return;
  }

  try {
    foo();
  } catch (const std::exception &e) {
    std::cout << "Fatal error (foo): " << e.what() << std::endl;
    return;
  }

  try {
    ... 
  } catch (const std::exception &e) {
    std::cout << "Fatal error: " << e.what() << std::endl;
    return;
  }
  ...
}

It doesn't look good. Instead, I can update foo:

void foo()
{
  try {
    ..
  } catch (const std::exception &) {
    std::cout << "Foo failed. The reason is:" << std::endl;
    throw;
  }
}

However, I do not like solution, too (maybe, because error logging is split). What is the right way to raise the exception upward?

\$\endgroup\$
  • \$\begingroup\$ I'd go for the last one. As it has the least chance of creating weird issues. However, I'd not ever throw (then again, I never used C++ Exceptions, just Python and Java). And I've used it in the Better-to-Ask-Forgiveness kind of way. \$\endgroup\$ – Stolas Feb 25 '14 at 15:34
  • \$\begingroup\$ Is this for exceptions which you throw, or for exceptions which are thrown by the STL? \$\endgroup\$ – ChrisW Feb 25 '14 at 15:51
  • \$\begingroup\$ @ChrisW - It's some exception inherited from std::exception (mostly std::runtime_error). \$\endgroup\$ – Loom Feb 25 '14 at 20:49
  • 1
    \$\begingroup\$ I'd use Boost.Exception (boost.org/doc/libs/1_55_0/libs/exception/doc/…), which allows you add information in the exception. In particular, see the "Nesting Exception" last paragraph of boost.org/doc/libs/1_55_0/libs/exception/doc/exception_ptr.html. \$\endgroup\$ – ddevienne Feb 27 '14 at 12:09
  • \$\begingroup\$ @ddevienne - Thank you. Interesting idea. I'll try to implement this approach myself. Unfortunately, I do not know Boost.Exceptions enough. May be somebody else can implement it. \$\endgroup\$ – Loom Feb 27 '14 at 14:13
7
\$\begingroup\$

You can re-throw an exception:

int main() {
    ...   
    try {
        ...
        try
        {
            foo();
        }
        catch(std::exception const& e) {
            std::cout << "Fatal error: " << e.what() << std::endl;

            throw; // re-throw the exception.
                   // or you could throw a different exception.
        }
        ...   
    } catch (const std::exception &e) {
        std::cout << "Fatal error: " << e.what() << std::endl;
        return;   
    }
    ... 
}
\$\endgroup\$
4
\$\begingroup\$

Instead of ...

  • Catching the exception
  • Printing a message
  • Returning gracefully (from main)

... you can ...

  • Not catch the exception
  • Print a stack trace
  • Abort execution

I'm not sure you can print the type of exception (using the what() method) if you do this, but a stack trace tells you not only that it happened inside foo but also in which subroutine of foo.

A Google search suggests how to get a stack trace from a C++ exception; for example this article looks useful (you'll get more-specific information if you specify a specific O/S in your Google search).

Advantages of this over catching an exception are:

  • Don't clutter your code with catch statements
  • A complete (deep) stack trace may be more useful than just knowing that it happened somewhere inside foo

(This may not work: this comment says that it's implementation-defined whether the stack is unwound before the terminate handler is called.)


If you're catching exceptions which you throw yourself, then you can have the best of both worlds (a catch and a stack trace): define a type of exception which captures a stack trace in its constructor (when it's thrown), then you can print the stack trace when you catch it.

\$\endgroup\$
1
\$\begingroup\$

Here I assume you want to handle exceptions from different fragments/classes inside main and take action accordingly.

You can use Macros to create new Exception and throw the exception to differentiate exceptions in case you have to differentiate.

#define CREATE_EXCEPTION(EXCEPTION_NAME) \
class EXCEPTION_NAME : public std::exception \
{ \
      std::string msg; \
      public: \
       EXCEPTION_NAME(std::string mesg):msg(mesg){} \
       std::string getMessage(){ return msg;}\
       ~EXCEPTION_NAME()throw (){}\
}; 
#define CATCH_THROW_EXCEPTION(CATCH_EXCEPTION,THROW_EXCEPTION)    \
     catch (CATCH_EXCEPTION &e) { \
    std::cout << "Foo failed. The reason is:" << std::endl; \
    throw THROW_EXCEPTION(e.what()); \
    }

CREATE_EXCEPTION(Foo_Exception);
void foo()
{
  try {
      ..
    }
    CATCH_THROW_EXCEPTION(std::exception,FOO_EXCEPTION) 
  }
}

int main() {
  ...
  try {
    ...
    foo();
    ...
  } 
  catch (Foo_Exception &e) {
    std::cout << "Fatal error:"<< e.getMessage() << std::endl;
    return;
  }
  catch (const std::exception &e) {
    std::cout << "Fatal error: "<< e.what() << std::endl;
    return;
  }
  ...
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.