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.
Related
I'm reading the book Inside the C++ Object Model and I got a paragraph as below:
There are a number of drawbacks to using statically initialized
objects. For example, if exception handling is supported, these
objects cannot be placed within try blocks. This can be particularly
unsatisfactory with statically invoked constructors because any throw
will by necessity trigger the default terminate() function within the
exception handling library.
If I get it correctly, it means that
MyGlobalObject obj;
int main()
{
try
{
// do something with obj here is unsatisfactory
}
catch(...){}
return 0;
}
is not good. But I don't know why. Why any throw will be necessity trigger the default terminate() function.
What it means is you can't catch exceptions from statically initialized objects because they are initialized before main() starts making it impossible to surround them with a try{} block.
MyGlobalObject obj; // this initializes before main() starts
int main()
{
try
{
// too late to protect the static initialized global
// with this try block during its initialization
// but any operations you perform on it afterwards
// inside this try{} block will be fine.
}
catch(std::exception const& e)
{
}
}
One solution to this is to put the static objects in a function like this:
MyGlobalObject& get_my_global_object()
{
// This will not initialize until this function
// is called for the first time.
static MyGlobalObject obj;
return obj;
}
int main()
{
try
{
// now if the global object throws during its
// initializatin the exception will be caught.
MyGlobalObject& obj = get_my_global_object();
}
catch(std::exception const& e)
{
}
}
I have some library (actually the tbb library compiled with a different compiler), throwing an exception before main() proper started. Is there a way to catch that?
int main() { std::cout << "Hello World" << std::endl; }
gives
terminating with unexpected foreign exception
Abort (core dumped)
if I link against said library (which is not used in this example, but in other code it will be).
Generally speaking, it is not possible in standard C++ to catch an exception that is thrown during construction of a global variable (which is outside scope of any function).
I believe the closest possibility is to use a function-try-block for the body of the constructor of the static.
class MyStatics
{
public:
MyStatics();
private:
X x; // construction may fail
Y y; // construction may fail
// etc
};
static MyStatics all_my_statics;
MyStatics::Mystatics() : x(), y() // implement using a function try block
try
{
if (some_condition) throw some_exception(); // construction may even fail here
}
catch (SomeException &)
{
// handler for SomeException
}
If an exception is thrown during construction of all_my_statics, then any fully-constructed members of it will be destructed (i.e. MyStatics members do not exist within such a catch block).
Within the catch block there aren't many options, after reporting about the caught exceptions. The main options will be;
throw (or rethrow) an exception (since the construction of MyStatics has failed). That exception will cause std::terminate() to be called.
terminate the program in some other way deemed to be "cleaner".
It is not a good idea to swallow an exception thrown during construction of a static since the program (e.g. within main()) will have no indication that statics it relies on have not been properly constructed.
It is more usual to place the static object within a function
X &the_x()
try
{
static X thing;
return thing;
}
catch (Whatever &)
{
// handler
}
Bear in mind that every call of the_x() will attempt to construct thing until one of them succeeds (i.e. if an exception is thrown the first time, the second call will attempt to construct thing, etc). However, if the first call of the_x() within the program can be identified and exceptions from it caught (i.e. wrap it in a try/catch) it is not necessary to catch exceptions from subsequent calls - since, if the first call doesn't throw, the construction of thing has succeeded, and it will not be constructed again.
I found this interesting source. It bases his construction on std::terminate functionality
He proposes to use a sort of global try...catch (you can't continue anymore to run, but you can act depending of exception):
[[noreturn]] void onTerminate() noexcept
{
if( auto exc = std::current_exception() ) {
// we have an exception
try{
rethrow_exception( exc ); // throw to recognize the type
}
catch( MyException const& exc ) {
// additional action
}
catch( MyOtherException const& exc ) {
// additional action
}
catch( std::exception const& exc ) {
// additional action
}
catch( ... ) {
// additional action
}
}
std::_Exit( EXIT_FAILURE );
}
and to register this caller when an exception occurred, earliest possible:
const auto installed{ std::set_terminate(&handler) };
int main() {
// run...
}
But you have to know that you can't be sure that std::set_terminate will be called before any instanciation.
What is a good way in C++ to detect in a destructor that it is being run during unwind of the stack due to an exception being thrown as opposed to a normal exit of scope triggering the destructor? I'd like to know so that I can create a class that has some cleanup code that is always run on normal exit but skipped when an exception occurs.
std::uncaught_exception() (defined in <exception>) will tell you in your destructor if it was called because of an exception:
class A
{
public:
~A()
{
if (std::uncaught_exception()) {
// Called because of an exception
} else {
// No exception
}
}
};
Probably this article will help you. The article will show you the problems with std::uncaught_exception() and contains an advice how to deal with exceptions in destructors.
Don't do that unless you have a good reason. The stack unwinding is such a language feature that all automatic objects inside try block will be enforced to deallocate, so that the resources inside them have a chance to release.
You want skip cleanup in dtor during stack unwinding, which bypasses the original intention of it. And you'll run the risk of leaking resources.
Example
class CDBConnection
{
public:
CDBConnection()
{
m_db.open();
}
~CDBConnection()
{
if (!std::uncaught_exception())
m_db.close();
// if this is called during a stack unwinding,
// your DB connection will not be closed for sure.
// That's a resource leakage.
}
//..
private:
DB m_db;
};
void main()
{
//..
try
{
// code that may throw
CDBConnection db;
//..
}
catch(const CDBException& exp)
{
// properly handle the exception
}
}
Here is one way I can think of, but it seems clumsy:
{
myCleanupClass unwindAction;
try {
// do some work which may throw exception.
} catch (...) {
unwindAction.disableDestructorWork();
throw;
}
}
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?
Suppose I construct a RAII object, and that object may fail to construct. How do I handle this?
try {
std::vector<int> v(LOTS);
// try scope ends here because that's what the catch is for
} catch( const std::bad_alloc& ) {
// ...
}
// v? what v?
Granted, the default constructor of std::vector won't throw and that can help, but this is not the general case. A constructor may very well throw. If I want to handle any resource acquisition failure, how do I do that while still being able to proceed if it doesn't throw?
Edit: To clarify, my issue is that if a resource fails to acquire then I might want to try again, and so on. Maybe I can try acquiring an alternative resource.
Depends what you mean by "proceed". Whatever operation requires the resource will fail: that's what "requires" means. So when you want to continue after an error, you might end up writing code like this:
void something_using_RAII(thingummy &t) {
vector<int> v(t.size_required);
// do something using v
}
...
for each thingummy {
try {
something_using_RAII(this_thingummy);
} catch(const std::bad_alloc &) {
std::cerr << "can't manage that one, sorry\n";
}
}
That's why you should only catch exceptions when there's something worthwhile you can do with them (in this case, report failure and move on to the next thingummy).
If you want to try again on failure, but only if the constructor fails, not if anything else fails:
while(not bored of trying) {
bool constructor_failed = true;
try {
vector<int> v(LOTS);
constructor_failed = false;
// use v
} catch(...) {
if (!constructor_failed) throw;
}
}
This is more-or-less how std::new_handler works - the handler is called in the catch clause of a similar loop, although with no need for a flag.
If you want to try a different resource on failure:
try {
vector<int> v(LOTS);
// use v
} catch(...) try {
otherthing<int> w(LOTS);
// use w
} catch(...) {
// failed
}
If "use v" and "use w" are basically the same code, then refactor into a function and call it from both places. Your function is doing quite a lot at this point.
If an RAII constructor throws, all resources bound to RAII objects prior to the throwing point will be cleaned up properly. The C++ rules are sensibly designed to guarantee that.
If your v construction throws because of a bad_alloc then any RAII object created prior to v in the try block will be properly cleaned up.
So if you consequently use RAII, you don't need a manual try / catch like that, because the RAII objects handle cleanup for you. If you do need it for some reason, in the case above you could use swap like the following.
std::vector<int> v;
try {
std::vector<int> vtry(LOTS);
v.swap(vtry); // no-throw
} catch( const std::bad_alloc& ) {
// ...
}
// v!
If v can't be created, all the code that tries to use v can't be executed. Move the catch after the code that code uses v, in a place where it is reasonable to continue execution if there is no v.
All code that uses v needs to be in the try block. If the question is how to then narrow down the code which threw the exception, you can use some kind of flag to indicate where in the try block you are, like this:
string flag;
try
{
flag = "creating vector<int> v";
std::vector<int> v(LOTS);
flag = "performing blaggity bloop";
blaggity_bloop();
flag = "doing some other stuff";
some_other_stuff();
}
catch( const std::bad_alloc& )
{
cerr << "Bad allocation while " << flag << endl;
}