Reputation: 482
I just finished implementing a basic exception system for my OpenGL + GLUT game. The exception i throw to exit the game is handled just fine, as well as some other assert exceptions, but then I tried to cause images to fail loading by removing the image folder and that particular exception doesn't seem to get caught. It causes the application to close with the message "This application requested the runtime to terminate in an unusual way".
This is the try/catch block that handles all of the exceptions, it's an inline static method of the application class (it's in the header file because it's a template function):
#pragma once
#include "logging.hpp"
#include "utils.hpp"
#include "throwables.hpp"
#include <cassert>
#include <exception>
namespace core
{
class application
{
public:
static const char * const tag;
template <class T>
static int run(int argc, char *argv[], const int width, const int height,
int x, int y, const char * const title) throw (const std::exception &)
{
int res = 0;
logging * const log = logging::get();
try
{
assert(log != NULL);
log->setverbosity(logging::info);
dbgcode(log->setverbosity(logging::verbose));
T * const g = T::get();
if (!g)
{
log->wtf(tag, "run: g is NULL! are we out of memory?");
throw core::assertexception();
}
T::envinit(argc, argv);
g->initialize(width, height, x, y, title);
g->run();
}
catch(const core::exitexception &e)
{
// hopefully everything is deallocated properly this way
log->i(tag, "run: exit message recieved");
res = 0;
}
catch(const core::assertexception &e)
{
utils::unexpectederror(title);
res = 1;
}
catch(const core::errorexception &e)
{
utils::error(title);
res = 1;
}
log->i(tag, strfmt() << "exiting with code " << res);
return res;
}
};
}
and this is the code that throws the exception that is never handled (it is executed inside g->run, so it is within the try block):
void sprite::load(const char * const filename) throw (const assertexception &, const errorexception &)
{
if (!filename) // this exception is handled perfectly
{
log->wtf(tag, strfmt() << "load: filename is NULL! what the hell did you pass me?" << img);
throw assertexception();
}
fromtex = false;
// generate and bind a DevIL image
ilGenImages(1, &img);
ilBindImage(img);
// attempt to load the sprite as a DevIL image
if (!ilLoadImage(filename)) // this exception is never caught even if I change this to if(true)
{
log->e(tag, strfmt() << "load: failed to load " << filename << ", image id = " << img);
throw errorexception(); // never caught when thrown
}
...
Here are my throwables.hpp / throwables.cpp where I define all of my custom exceptions:
hpp:
#pragma once
#include <stdexcept>
#include <string>
namespace core
{
class exception : public std::runtime_error
{
public:
exception(const std::string &info);
};
class assertexception : public exception
{
public:
assertexception();
};
class errorexception : public exception
{
public:
errorexception();
};
class exitexception : public exception
{
public:
exitexception();
};
}
cpp:
#include "throwables.hpp"
namespace core
{
exception::exception(const std::string &info)
: std::runtime_error(info)
{}
// assertexception
assertexception::assertexception()
: exception("an assertion has occurred - check the log file")
{}
// errorexception
errorexception::errorexception()
: exception("an error has occurred - check the log file")
{}
// exitexception
exitexception::exitexception()
: exception("exit message recieved")
{}
}
EDIT: also, here are those utils::*error funcs I call:
void unexpectederror(const wxString &gamename)
{
// TODO: make everything unicode friendly
// TODO: get all strings from xmls for easy localization
wxSafeShowMessage(gamename + wxT(" - Unexpected error"),
wxT("An unexpected error has occurred. Please report this bug")
wxT(" and attach your lastsession.log file"));
}
void error(const wxString &gamename)
{
wxSafeShowMessage(gamename + wxT(" - Error"),
wxT("An error has occurred. Please check your lastsession.log")
wxT(" for more info and check for <error> messages. Please report it if you believe it is a bug"));
}
void error(const wxString &title, const wxString &text)
{
wxSafeShowMessage(title, text);
}
std::exception is being caught in main, by the way:
#include "dungeoncrawler.hpp"
#include "application.hpp"
using namespace core;
int main(int argc, char *argv[])
{
static const char * const tag = ".main";
static const char * const title = "DungeonCrawler";
try
{
return application::run<dungeoncrawler::game>(argc, argv, 800, 450, -1, -1, title);
}
catch(const std::exception &e)
{
utils::unhandledexception(title, e);
logging::get()->wtf(tag, "unhandled exception, exiting with code 0");
return 0;
}
assert(false); // this code should never be reached
logging::get()->wtf(tag, "what?! this code should be unreachable! exiting with code 0");
utils::error(wxString(title), wxT("Unexpected behaviour occurred. Please report this bug to the developer"));
return 0;
}
Upvotes: 0
Views: 499
Reputation: 63775
The problem is with how this function is declared.
void sprite::load(const char * const filename) throw (const assertexception &, const errorexception &)
That function is promising to only throw exceptions assertexception
and errorexception
.
If any other exception is thrown from that function, std::unexpected()
will be called and terminate your program. This will happen, for example, if the standard library or any other library unaware of those exception classes throw
.
Remove that throw
clause to fix it.
See this Herb Sutter article to learn more.
Upvotes: 2