I have this code..
CEngineLayer::CEngineLayer(void)
{
// Incoming creation of layers. Wrapping all of this in a try/catch block is
// not helpful if logging of errors will happen.
logger = new (std::nothrow) CLogger(this);
if(logger == 0)
{
std::bad_alloc exception;
throw exception;
}
videoLayer = new (std::nothrow) CVideoLayer(this);
if(videoLayer == 0)
{
logger->log("Unable to create the video layer!");
std::bad_alloc exception;
throw exception;
}
}
IEngineLayer* createEngineLayer(void)
{
// Using std::nothrow would be a bad idea here as catching things thrown
// from the constructor is needed.
try
{
CEngineLayer* newLayer = new CEngineLayer;
return (IEngineLayer*)newLayer;
}
catch(std::bad_alloc& exception)
{
// Couldn't allocate enough memory for the engine layer.
return 0;
}
}
I've omitted most of the non-related information, but I think the picture is clear here.
Is it okay to manually throw an std::bad_alloc instead of try/catching all of the layer creations individually and logging before rethrowing bad_allocs?
Just to answer the question (since nobody else seems to have answered it), the C++03 standard defines std::bad_alloc as follows:
namespace std {
class bad_alloc : public exception {
public:
bad_alloc() throw();
bad_alloc(const bad_alloc&) throw();
bad_alloc& operator=(const bad_alloc&) throw();
virtual ˜bad_alloc() throw();
virtual const char* what() const throw();
};
}
Since the standard defines a public constructor, you'd be perfectly safe to construct and throw one from your code. (Any object with a public copy constructor can be thrown, IIRC).
You don't need to do that. You can use the parameterless form of the throw statement to catch the std::bad_alloc exception, log it, then rethrow it:
logger = new CLogger(this);
try {
videoLayer = new CVideoLayer(this);
} catch (std::bad_alloc&) {
logger->log("Not enough memory to create the video layer.");
throw;
}
Or, if logger is not a smart pointer (which it should be):
logger = new CLogger(this);
try {
videoLayer = new CVideoLayer(this);
} catch (std::bad_alloc&) {
logger->log("Not enough memory to create the video layer.");
delete logger;
throw;
} catch (...) {
delete logger;
throw;
}
I personally DO throw it if I use some custom allocator in STL containers. The idea is to present the same interface- including in terms of behavior- to the STL libraries as the default std::allocator.
So, if you have a custom allocator (say, one allocating from a memory pool) and the underlying allocate fails, call "throw std::bad_alloc". That guarantees the caller, who 99.9999% of the time is some STL container, will field it properly. You have no control over what those STL implementations will do if the allocator returns a big fat 0- it is unlikely to be anything you'll like.
Another pattern is to use the fact that the logger is subject to RAII, too:
CEngineLayer::CEngineLayer( )
{
CLogger logger(this); // Could throw, but no harm if it does.
logger.SetIntent("Creating the video layer!");
videoLayer = new CVideoLayer(this);
logger.SetSucceeded(); // resets intent, so CLogger::~CLogger() is silent.
}
This scales cleanly if there are multiple steps. You just call .SetIntent repeatedly. Normally, you only write out the last intent string in CLogger::~CLogger() but for extra verbose logging you can write out all intents.
BTW, in your createEngineLayer you might want a catch(...). What if the logger throws a DiskFullException?
Related
I added a bunch of exceptions to my hash table class to deal with various issues that might come up. They are mostly constructed like this:
std::string msg = std::string("I made doodoo, some value: ") + std::tostring(value);
throw std::exception(msg.c_str());
Some of the exceptions are part of normal operation, for example there is one that says the table is full and the thing that catches it then rebuilds the table into a bigger one. I discovered that this puts a sizable dent in the performance though, I suspect its all the string construction. At the same time though, I want the exceptions to be meaningful and make sense to somebody who doesn't know what the code numbers I come up with mean. Whats a good way to deal with this?
Ideally you should be creating custom exception classes from std::exception. That way when you create your catch blocks, you can have a specific catch for each of your exceptions. Example:
class MyException; // Inherits from std::exception.
class MyOtherException; // Inherits from std::exception.
void foo()
{
if (bar)
throw MyException();
if (baz)
throw MyOtherException();
// do stuff.
}
int main()
{
try
{
foo();
}
catch(const MyException &ex)
{
// Handle MyException.
}
catch (const MyOtherException &ex)
{
// Handle MyOtherException.
}
}
Creating your own exception classes affords you a lot more flexibility because it allows you to attach additional information to your exceptions, as well as handling different exception types as described above.
class MyException : public std::exception
{
private:
std::string m_description;
int m_userId;
public:
MyException(const std::string &errorDescription = "Unhandled exception", const int userId) :
m_description(errorDescription),
m_userId(userId)
{
}
int get_user_id() const
{
return m_userId;
}
virtual const char *what() const
{
return m_description.c_str();
}
}
The main problem with your code (at least how you described it) however is that you seem to be controlling your program flow with exceptions. Exceptions are not designed to be fast constructs, they're designed for exceptional cases that would, if not handled, cause your program to crash. Attempting to use exceptions in place of if statements is going to make your code very slow, very hard to read, and even harder to understand/maintain.
To take from your example: if you're adding to a hash table, and need to resize the table, why do you need to throw an exception, when you could just resize it? This is exactly how an std::vector works. If you do a push_back() on a vector and vector.capacity() < vector.size() + 1, the vector will internally re-allocate the buffer so that the new item can be added. The only time an exception might be thrown is if you run out of memory. The caller isn't aware of any of this, it just calls vector.push_back(...).
I have a piece of network code that throws various exception which are all caught under a general catch exception statement.
try {
network code
} catch (Exception e) {
freeaddrinfo(some_address);
}
The problem with this method is the freeaddrinfo within the exception. Not all cases of exception can/should call freeaddrinfo and in my specific case freeaddrinfo should not be called when there is an invalid address that is passed into the network code to connect somewhere. My idea of solving this problem is to retrieve the error code that was thrown by this exception and to possibly use this in combination with e.to_string to deal with this edge case. From what I have learned from Effective Java, this is a fragile way of dealing with this problem. What do you recommend I should do?
In C++, the usual way to release a resource after an exception is not to catch the exception, but to wrap the resource in an object whose destructor is responsible for releasing. That way, it is released when the management object goes out of scope (or is otherwise destroyed), whether or not an exception is thrown. This technique is known as RAII.
A (very basic) management object might look like:
struct AddressInfo {
addrinfo * info;
// Constructor takes ownership of resource
explicit AddressInfo(addrinfo * info) : info(info) {}
// Destructor releases resource
~AddressInfo() {freeaddrinfo(info);}
// Prevent shallow copying, so only one object manages the resource
AddressInfo(AddressInfo const &) = delete;
void operator=(AddressInfo const &) = delete;
};
Then your code would become:
// some network code
AddressInfo address(some_address);
// some more network code
with no need for any exception handling or manual clean-up code.
If you insist on using exceptions, then the network code should raise a very specific exception (type) based on the nature of the error. That is, the network code should raise an exception that, by its very nature, implies whether freeaddrinfo() can be invoked.
Create more specific exceptions and throw them? Then you can catch those first, before falling back on the general catch.
try {
network code
}
catch (SomeException1 e) { freeaddrinfo(some_address); }
catch (SomeException2 e) { freeaddrinfo(some_address); }
catch (Exception e) { }
1) For convenience I have my entire program in a try block. This way I can throw an exception at any point in my code and know that it will be handled the same way. As the program becomes larger will this technique cause a hit in performance?
2) If objects are de-allocated when out of scope, why would throwing a temporary object be valid? e.g.:
class Error : public std::exception
{
private:
char *m;
private:
Error(char *l) : m(l) {}
virtual char *what()
{
return m;
}
};
int main()
{
try
{
throw Error("test");
}
catch(std::exception &e)
{
puts(e.what());
return -1;
}
return 0;
}
In the throw statement, why wouldn't the temporary object become invalid since it's been declared only in the try scope?
3) With Windows operating systems of a language other than English, would the what() member of the STL exception class still return a char* string? Or could it return a wchar_t* string?
Technically you don't throw the actual object, you throw a copy of it. That's why you can get away with throwing a temporary. Catching a reference also gets a reference to the copy.
This can bite you if you rethrow an exception from within a catch block, you can fall victim to the slicing problem. That's why you don't do:
catch (std::exception & e)
{
throw e; // bad, always throws std::exception rather than what was caught
}
But rather
catch (std::exception & e)
{
throw; // good, rethrows the exact copy that you caught without making another copy
}
P.S. There's no rule saying you couldn't return a UTF-8 string from what. It would be up to you to convert it to UTF-16 for Windows I/O. The standard exception classes were never explicitly designed or extended for Unicode, nor are any non-standard extensions added just for Windows.
1)
Having the whole program in a try block will not incur any performance hit, apart from that incurred by having exceptions enabled at all
2)
It is OK because you are throwing by value. Throwing by value means that whatever you throw is copied when thrown. So throwing any temporary is perfectly valid because a copy is made.
3)
The std::exception class, as far as I can determine, can only ever throw a char*. However you could always subclass it and implement support for wchar if you wanted.
It is worth noting that you shouldn't just have a try catch around main() if that is what you were intending.
I have an object on the stack for which I wish its destructor to skip some work when the destructor is being called because the stack is being unwound due to a specific exception being thrown through the scope of the object on the stack.
Now I could add a try catch block inside the scope of the stack item and catch the exception in question and notify the stack object to not run the work to be skipped an then rethrow the exception as follows:
RAII_Class pending;
try {
doSomeWorkThatMayThrowException();
} catch (exceptionToSkipPendingDtor &err) {
pending.notifySkipResourceRelease();
throw;
}
However, I'm hoping there is a more elegant way to do this. For example imagine:
RAII_Class::~RAII_Class {
if (detectExceptionToSkipPendingDtorBeingThrown()) {
return;
}
releaseResource();
}
You can almost do this with std::uncaught_exception(), but not quite.
Herb Sutter explains the "almost" better than I do: http://www.gotw.ca/gotw/047.htm
There are corner cases where std::uncaught_exception() returns true when called from a destructor but the object in question isn't actually being destroyed by the stack unwinding process.
You're probably better off without RAII because it doesn't match your use case. RAII means always clean up; exception or not.
What you want is much simpler: only release resource if an exception is not throw which is a simple sequence of functions.
explicitAllocateResource();
doSomeWorkThatMayThrowException();
explicitReleaseResource(); // skipped if an exception is thrown
// by the previous function.
I would do it the other way around - explicitly tell it to do its work if no exception was thrown:
RAII_Class pending;
doSomeWorkThatMayThrowException();
pending.commit(); // do or prepare actual work
This seems to circumvent the main reason to use RAII. The point of RAII is that if an exception happens in the middle of your code you can still release resources/be destructed properly.
If this isn;t the semantic you want, then don't use RAII.
So instead of:
void myFunction() {
WrapperClass wc(acquireResource());
// code that may throw
}
Just do:
void myFunction() {
Resource r = acquireResource();
// code that may throw
freeResource(r);
}
If the code in the middle throws, the resource won't be freed. This is what you want, rather than keeping RAII (and keeping the name) but not implementing RAII semantics.
Looks like bool std::uncaught_exception(); does the trick if you want to have this behavior for every exception, not just special ones!
You can do without a try-catch:
RAII_Class pending;
doSomeWorkThatMayThrowException(); // intentional: don't release if throw
pending.releaseResource();
Alternatively, you can try a little harder with RAII:
struct RAII_Class {
template<class Op>
void execute(Op op) {
op();
releaseResources();
}
private:
void releaseResources() { /* ... */ }
};
int main(int argc, char* argv[])
{
RAII_Class().execute(doSomeWorkThatMayThrowException);
return 0;
}
Although it would be a kludge at best, if you own the code for the exception class you're interested in, you could add a static data member to that class (bool) that would be set to "true" in the constructor for objects of that class, and false in the destructor (might need to be an int that you increment/decrement instead). Then in the destructor of your RAII class, you can check std::uncaught_exception(), and if true, query the static data member in your exception class. If you get true (or > 0) back, you've got one of those exceptions--otherwise you ignore it.
Not very elegant, but it would probably do the trick (as long as you don't have multiple threads).
I found this website with an interesting discussion about std::uncaught_exception() and an alternative solution to your question that seems much more elegant and correct to me:
http://www.gotw.ca/gotw/047.htm
// Alternative right solution
//
T::Close() {
// ... code that could throw ...
}
T::~T() /* throw() */ {
try {
Close();
} catch( ... ) {
}
}
In this way you're destructor does only one thing and you're protected against throwing an exception during an exception (which I assume is the problem you're trying to solve).
Is it OK to have the following code in my constructor to load an XML document into a member variable - throwing to caller if there are any problems:
MSXML2::IXMLDOMDocumentPtr m_docPtr; //member
Configuration()
{
try
{
HRESULT hr = m_docPtr.CreateInstance(__uuidof(MSXML2::DOMDocument40));
if ( SUCCEEDED(hr))
{
m_docPtr->loadXML(CreateXML());
}
else
{
throw MyException("Could not create instance of Dom");
}
}
catch(...)
{
LogError("Exception when loading xml");
throw;
}
}
Based on Scott Myers RAII implementations in More Effective C++ he cleanups if he alocates any resources i.e. pointers:
BookEntry::BookEntry(const string& name,
const string& address,
const string& imageFileName,
const string& audioClipFileName)
: theName(name), theAddress(address),
theImage(0), theAudioClip(0)
{
try { // this try block is new
if (imageFileName != "") {
theImage = new Image(imageFileName);
}
if (audioClipFileName != "") {
theAudioClip = new AudioClip(audioClipFileName);
}
}
catch (...) { // catch any exception
delete theImage; // perform necessary
delete theAudioClip; // cleanup actions
throw; // propagate the exception
}
}
I believe I am alright in just allowing exceptions to be thrown from CTOR as I am using a smart pointer(IXMLDOMDocumentPtr).
Let me know what you think....
C++ guarantees that in case of an exception all fully constructed objects will be destroyed.
Since m_docPtr is a member of class Configuration it will have been fully constructed before the class Configuration constructor body begins, so if you throw an exception from class Configuration body as you intended in your first snippet m_docPtr will be destroyed.
Do you plan to do anything in the catch block? If nothing, you probably do not need the try catch. On windows, I believe that catch(...) catches hardware interrupts (experts please correct), something to keep in mind.