2013-04-21 47 views
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; 
     } 
    }; 
} 

,這是

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,我定義所有:拋出,它永遠不會處理的異常(它裏面G-執行>運行,所以它是try塊內)的代碼我的自定義例外:

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

編輯:另外,在這裏是指那些utils的:: *錯誤funcs中我打電話:

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 ::例外是被抓在主,順便說一句:

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

可能值得注意的是,在任何時候你都不會捕獲'std :: exception'。雖然它是你所定義的所有優秀和吸引人的東西,但是當你沒有寫*的某些代碼拋出一個異常時,它會全部崩潰。 – 2013-04-21 16:24:25

+0

std ::異常被捕獲主 – 2013-04-21 16:27:39

回答

2

問題在於如何聲明這個函數。

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

該函數承諾只拋出異常assertexceptionerrorexception

如果從該函數拋出任何其他異常,將調用std::unexpected()並終止您的程序。例如,如果標準庫或任何其他庫不知道那些異常類別throw,則會發生這種情況。

刪除那throw子句來解決它。

請參閱this Herb Sutter article瞭解更多信息。

+0

*注意:我在這裏使用一些通靈能力,因爲該功能的全部細節未知* – 2013-04-21 16:33:46

+0

哦哇。這不是問題,但它幫助我弄清楚了。 sprite :: load被dungeoncrawler :: game :: initialize調用,它只被聲明爲拋出assertexception。這就是爲什麼它不處理其他的!謝謝 – 2013-04-21 16:38:58

+0

@FrancescoNoferi這是個好消息!如果你有一分鐘​​,請閱讀鏈接的文章。簡短的說法是函數聲明中的'throw'子句經常被證明比他們的價值更麻煩。 – 2013-04-21 16:46:15

相關問題