c++ exception : throwing std::string

C++ExceptionStl

C++ Problem Overview


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;
	}
}

C++ Solutions


Solution 1 - C++

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.

Solution 2 - C++

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;
  }
}

Solution 3 - C++

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.

Solution 4 - C++

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.

Solution 5 - C++

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

Solution 6 - C++

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.

Solution 7 - C++

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"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPalad1View Question on Stackoverflow
Solution 1 - C++christopher_fView Answer on Stackoverflow
Solution 2 - C++PierreBdRView Answer on Stackoverflow
Solution 3 - C++anonView Answer on Stackoverflow
Solution 4 - C++Daniel SpiewakView Answer on Stackoverflow
Solution 5 - C++Michael BurrView Answer on Stackoverflow
Solution 6 - C++Eric LeschinskiView Answer on Stackoverflow
Solution 7 - C++GPMuellerView Answer on Stackoverflow