tags:

views:

7633

answers:

7

Hello,

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;
  }
}
+3  A: 

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
+14  A: 

A few principle:

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) {}
   const char* what() const throw() { return s.c_str(); }
}

And then 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
Would it not be better to derive from std::runtime_exception?
Martin York
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
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
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
A: 

Thanks. Is there a builtin exception type somewhere in the STL?

Here's the rewritten exception handler then:

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;
    delete caught;
  }
}
Palad1
still isn't going to work:scope resolution operator in "Foo:Caller" needs to be "::", two colonsstd::string has no capital 'S'
Ben Voigt
+2  A: 

All these work:

#include <iostream>
using namespace std;

void f() { throw string("foo"); }
void g() { throw new string("foo"); }
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.

+17  A: 

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
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
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
A: 

Thanks to everyone. Faster than asking on IRC and much better S/N ratio. Cheers!

Palad1
+1  A: 

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