0

我刚刚为我的 OpenGL + GLUT 游戏实现了一个基本的异常系统。我抛出退出游戏的异常处理得很好,以及其他一些断言异常,但是我试图通过删除图像文件夹来导致图像加载失败,并且该特定异常似乎没有被捕获。它会导致应用程序关闭并显示消息“此应用程序请求运行时以异常方式终止”。

这是处理所有异常的 try/catch 块,它是应用程序类的内联静态方法(它在头文件中,因为它是一个模板函数):

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

这是抛出从未处理过的异常的代码(它在 g->run 中执行,所以它在 try 块中):

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
    }

    ...

这是我的 throwables.hpp / throwables.cpp,我在其中定义了所有自定义异常:

惠普:

#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();
    };
}

cp:

#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")
    {}
}

编辑:另外,这里是我调用的那些 utils::*error 函数:

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 被 main 捕获:

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

1 回答 1

2

问题在于如何声明这个函数。

void sprite::load(const char * const filename) throw (const assertexception &, const errorexception &)

该函数承诺只抛出异常assertexceptionerrorexception.

如果该函数抛出任何其他异常,std::unexpected()将被调用并终止您的程序。例如,如果标准库或任何其他库不知道这些异常类,就会发生这种情况throw

删除该throw子句以修复它。

请参阅此 Herb Sutter 文章以了解更多信息。

于 2013-04-21T16:29:47.243 回答