84

I would like to throw an exception when my C++ methods encounter something weird and can't recover. Is it OK to throw a std::string pointer?

Here's what I was looking forward to doing:

void Foo::Bar() {
    if(!QueryPerformanceTimer(&m_baz)) {
        throw new std::string("it's the end of the world!");
    }
}

void Foo::Caller() {
    try {
        this->Bar(); // should throw
    }
    catch(std::string *caught) { // not quite sure the syntax is OK here...
        std::cout << "Got " << caught << std::endl;
    }
}
LogicStuff
  • 19,397
  • 6
  • 54
  • 74
Palad1
  • 853
  • 1
  • 7
  • 8

7 Answers7

104

Yes. std::exception is the base exception class in the C++ standard library. You may want to avoid using strings as exception classes because they themselves can throw an exception during use. If that happens, then where will you be?

boost has an excellent document on good style for exceptions and error handling. It's worth a read.

christopher_f
  • 1,975
  • 1
  • 13
  • 12
  • 22
    Side note: std::terminate will be called if the exception object itself throws, that's where you'll be (and it ain't pretty!) – Alaric Sep 26 '08 at 01:01
  • 6
    See http://www.gotw.ca/publications/mill16.htm for one argument about why bothering with allocations throwing exceptions is a waste of time. Another argument aginst this answer is that std::runtime_exception and family does it, so why don't you? – Greg Rogers Oct 29 '08 at 14:57
68

A few principles:

  1. you have a std::exception base class, you should have your exceptions derive from it. That way general exception handler still have some information.

  2. Don't throw pointers but object, that way memory is handled for you.

Example:

struct MyException : public std::exception
{
   std::string s;
   MyException(std::string ss) : s(ss) {}
   ~MyException() throw () {} // Updated
   const char* what() const throw() { return s.c_str(); }
};

And then use it in your code:

void Foo::Bar(){
  if(!QueryPerformanceTimer(&m_baz)){
    throw MyException("it's the end of the world!");
  }
}

void Foo::Caller(){
  try{
    this->Bar();// should throw
  }catch(MyException& caught){
    std::cout<<"Got "<<caught.what()<<std::endl;
  }
}
PierreBdR
  • 42,120
  • 10
  • 46
  • 62
  • 5
    Would it not be better to derive from std::runtime_exception? – Martin York Sep 25 '08 at 18:06
  • Note that christopher_f's argument is still valid: Your exception could throw an exception at construction... Food for thought, I guess... :-D ... I could be wrong, but exception are supposed to be catched through their const-reference, no? – paercebal Sep 25 '08 at 21:10
  • For the const-reference, it is possible, but not mandatory. I wondered a while about it ... didn't find any reference for or against it. – PierreBdR Sep 26 '08 at 12:56
  • const ref here is only useful so you don't accidentally modify the exception in the catch-block. which you won't do anyway so just catch by nonconst ref –  Jan 06 '09 at 20:48
  • I tried this code, there was a compilation error, something about the destructor method... – dividebyzero Jun 22 '13 at 19:19
  • Try adding: ``~MyException() throw () {}`` for a destructor – PierreBdR Jul 17 '13 at 14:07
  • But the exception may get copied for unspecified number of times before reaching to a catch block. What if the `string`'s copy ctor throws? Wouldn't `std::terminate()` be called? – Sam Oct 23 '18 at 19:17
26

All these work:

#include <iostream>
using namespace std;

//Good, because manual memory management isn't needed and this uses
//less heap memory (or no heap memory) so this is safer if
//used in a low memory situation
void f() { throw string("foo"); }

//Valid, but avoid manual memory management if there's no reason to use it
void g() { throw new string("foo"); }

//Best.  Just a pointer to a string literal, so no allocation is needed,
//saving on cleanup, and removing a chance for an allocation to fail.
void h() { throw "foo"; }

int main() {
  try { f(); } catch (string s) { cout << s << endl; }
  try { g(); } catch (string* s) { cout << *s << endl; delete s; }
  try { h(); } catch (const char* s) { cout << s << endl; }
  return 0;
}

You should prefer h to f to g. Note that in the least preferable option you need to free the memory explicitly.

Patrick M
  • 1,066
  • 8
  • 23
  • 1
    But isn't the throwing a `const char` pointer to a local variable a bug? Yes, of course I know that the compiler will place the c-string in the unmodified section which will not change address till an app running. But it is undefined; more over, what would be if this code was in a library that gone just after throwing an error? Btw, I too did many such a bad things in my project, I am just a student. But I should have thought about it... – Hi-Angel Aug 04 '14 at 14:21
  • 1
    @Hi-Angel There is no local variable; what is thrown there is a string literal, which has specific and well-defined treatment by the Standard in terms of lifetime, and your concerns are moot. See e.g. https://stackoverflow.com/a/32872550/2757035 If there was a problem here, basically no throwing of messages could ever work (at least not without requiring undue extra acrobatics/risk), so of course there isn't, and it's fine. – underscore_d Oct 06 '18 at 12:06
8

It works, but I wouldn't do it if I were you. You don't seem to be deleting that heap data when you're done, which means that you've created a memory leak. The C++ compiler takes care of ensuring that exception data is kept alive even as the stack is popped, so don't feel that you need to use the heap.

Incidentally, throwing a std::string isn't the best approach to begin with. You'll have a lot more flexibility down the road if you use a simple wrapper object. It may just encapsulate a string for now, but maybe in future you will want to include other information, like some data which caused the exception or maybe a line number (very common, that). You don't want to change all of your exception handling in every spot in your code-base, so take the high road now and don't throw raw objects.

Daniel Spiewak
  • 54,515
  • 14
  • 108
  • 120
8

In addition to probably throwing something derived from std::exception you should throw anonymous temporaries and catch by reference:

void Foo::Bar(){
  if(!QueryPerformanceTimer(&m_baz)){
    throw std::string("it's the end of the world!");
  }
}

void Foo:Caller(){
  try{
    this->Bar();// should throw
  }catch(std::string& caught){ // not quite sure the syntax is ok here...
    std::cout<<"Got "<<caught<<std::endl;
  }
}
  • You should throw anonymous temporaries so the compiler deals with the object lifetime of whatever you're throwing - if you throw something new-ed off the heap, someone else needs to free the thing.
  • You should catch references to prevent object slicing

.

See Meyer's "Effective C++ - 3rd edition" for details or visit https://www.securecoding.cert.org/.../ERR02-A.+Throw+anonymous+temporaries+and+catch+by+reference

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
4

Simplest way to throw an Exception in C++:

#include <iostream>
using namespace std;
void purturb(){
    throw "Cannot purturb at this time.";
}
int main() {
    try{
        purturb();
    }
    catch(const char* msg){
        cout << "We caught a message: " << msg << endl;
    }
    cout << "done";
    return 0;
}

This prints:

We caught a message: Cannot purturb at this time.
done

If you catch the thrown exception, the exception is contained and the program will ontinue. If you do not catch the exception, then the program exists and prints:

This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
3

Though this question is rather old and has already been answered, I just want to add a note on how to do proper exception handling in C++11:

Use std::nested_exception and std::throw_with_nested

Using these, in my opinion, leads to cleaner exception design and makes it unnecessary to create an exception class hierarchy.

Note that this enables you to get a backtrace on your exceptions inside your code without need for a debugger or cumbersome logging. It is described on StackOverflow here and here, how to write a proper exception handler which will rethrow nested exceptions.

Since you can do this with any derived exception class, you can add a lot of information to such a backtrace! You may also take a look at my MWE on GitHub, where a backtrace would look something like this:

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
GPMueller
  • 2,881
  • 2
  • 27
  • 36