\n |
[ トップページ ]
[ ____CommandPrompt ]
[ ____JScript ]
[ ____MySQL ]
[ ____Cygwin ]
[ ____Java ]
[ ____Emacs ]
[ ____Make ]
[ ____Perl ]
[ ____Python ]
[ ____OpenGL ]
[ ____C# ]
[ ____StyleSheet ]
[ ____C++ ]
[ ____Winsock ]
[ ____Thread ]
[ ____VisualStudio ]
[ ____C ]
[ ____Win32API ]
[ ____Lua ]
[ ____PhotoShop ]
ヘッダ検索
■ 例外(Exception)
C++ にはエラーを処理するための機構として例外というものが用意されている。
C スタイルの関数の戻値としてエラーを返す方法にとって代わる方法のこと。
エラーがプログラムの実行中に発生した場合に
例外オブジェクトというもの (これ自体がクラスのインスタンス)を生成します。
これを例外の送出(スロー)といい
例外オブジェクトを適切な方法で補足(キャッチ)して、 エラー処理をする。
例外をキャッチしたい範囲があれば try ブロックで処理をかいて
catch でリカバリをする処理をかく。
try // 例外の発生し得る範囲
{
throw "例外が発生しました"; // 例外をスローする
}
catch( const char* str ) // 例外をキャッチする
{
std::cout < < str < < std::endl;
}
catch ブロックには、キャッチできる例外の型を指定する。
catch ( runtime_error ) {
}
// すべての例外型をキャッチする
catch ( ... ) {
}
WARNING
この指定はできない。コンパイルエラーとなる。
各関数はどの例外をなげるか宣言をする。
例外の仕様という。
throw() は例外を投げないことと宣言する。
throw( runtime_error ) は runtime_error 型( またはその派生型 )の例外をなげると説明をする
void func() throw( runtime_error );
■ 例外の使いどころ
例外は無視できない。
例外をなげる場合は、どこかでキャッチをしないとプログラムが終了する。
つまりエラーがあればその場で即死させることができる。
// エラーコードとして返す場合はチェックを無視できる。
ErrorCode fileopen( string &path ) {
if ( path ) {
return E_INVALID_PATH;
}
}
// 投げられた例外はどこかでとらえないとプログラムは終了する。
void fileopen( string &path ) throw( InvalidFilePath );
void fileopen( string &path ) {
if ( path ) {
throw InvalidFilePath( path );
}
}
制御ロジックがエラーハンドルロジックと分離できる
try {
add( a )
add( a )
add( a )
add( a )
}
catch ( ) {
// ここでまとめてエラーハンドル
}
try {
ret = add( a )
if ( ret ) {
}
add( a )
// エラーハンドル
if ( ret ) {
}
add( a )
if ( ret ) {
}
add( a )
}
catch ( ) {
}
■ 例外を捕捉する
全体で例外をキャッチするには main() 内でキャッチをする。
int main() {
try {
}
catch (...) {
}
return 0;
}
もし main で捕捉できない例外があれば、main() の実行前に発生した例外かもしれない。
静的なオブジェクトのコンストラク内で例外をとらえる。
■ 例外処理をカスタマイズする
■ terminate
投げられた例外がキャッチされないと、 terminate() が呼ばれる。
エラーのログをとり, リソースをすべて解放をして abort() をよぶ。
文字とおり最後の処理をする。
set_terminate() によって実装を変更できる。
void my_terminate() throw()
{
printf( "call my_terminate\n" );
char buf[256];
gets( buf );
// エラーのログをとり、フラッシュする。
}
void testfunc() throw( runtime_error )
{
throw runtime_error( "test" );
}
int main() {
set_terminate( my_terminate );
testfunc();
}
POINT
main() 実行前に静的なオブジェクトの初期化が実行される。
このときは 静的なオブジェクトのコンストラクタに set_terminate() をいれると捕捉をできる。
■ unexpected
仕様にない例外をなげると, unexpected() をよばれる。
デフォルトの処理は terminate() をよぶだけ。
set_unexpected() によって内容を変更できる。
unexpected() -> terminate() -> abort()
■ 例外クラスを捕捉する
例外はシステムで定義すみのクラスがある。
それ以外に任意の例外クラスを定義できる。
呼び出し元は自分がエラーハンドルできる例外型を指定できる。
init() {
try {
File->open();
}
catch ( InvalidFileException ) {
// InvalidFileException とその派生クラスの例外だけをとらえる。
// それ以外の例外は無視されて、さらに上の関数へ伝播する
}
}
void main() {
try {
init();
}
catch ( runtime_error ) {
// init() 以下で捕捉されない例外はここに届く。
}
}
POINT
catch で捕獲できる例外オブジェクトは任意の型を補足できる。
派生クラスもキャッチの対象になるので階層構造にしておくと便利。
throw; とするとキャッチした例外を再度スローすることになる。
つまり人に丸投げすることになる。
try - catch をするのは次の条件をみたすとき。
すべての関数よびだしで try - catch をする必要はない
WARNING
リカバリーできない例外をキャッチするのは問題を先送りにしているだけ
try {
}
catch () {
// 何もしない
}
例外がなげられたときは スタック上のオブジェクトは デストラクタが実行される
■ 例外クラスを定義する
POINT
例外は 基底クラスから必ず派生させる。
こうすることで main でキャッチオールブロックを用意できることになる
int main() {
try {
}
catch( exception e ) {
}
}
システムが提供する 例外クラスもある
class InvalidPath : public runtime_error {
public:
InvalidPath() throw();
};
■ コンストラクタの例外
コンストラクタも例外をなげることができる。
コンストラクタで例外を投げるということは
そのオブジェクトが未完全な状態でつくられる。
T::T() throw( runtime_error )
{
}
メンバオブジェクトのコンストラクトに失敗した場合は、
既にコンストラクト済みの他のオブジェクトのデストラクタがよばれる。
■ アンワインドプロセス
例外の実装は longjmp() と同じ。
関数外の場所に制御をうつす。
ただし 例外は スタックを戻してくれる。( unwind process )
スタック上のオブジェクトは デストラクタが実行される。
POINT
ただし /EHsc オプションをつけること
指定しないとデストラクタが実行されない。
■ GetCurrentProcessId
SYNTAX
DWORD GetCurrentProcessId();
DESC
呼び出し側プロセスのプロセス識別子が返す。
Kernel32.lib
■ internal
■ SymGetLineFromAddr
SYNTAX
BOOL SymGetLineFromAddr(
HANDLE hProcess,
DWORD dwAddr,
PDWORD pdwDisplacement,
PIMAGEHLP_LINE Line
);
DESC
指定されたアドレスに対応するソースコードの行を検索する
imagehlp.lib
■ GetFirstStackTrace
■ symgetodulebase
SYNTAX
DWORD SymGetModuleBase(
HANDLE hProcess, // 最初に SymInitialize() へ渡された、プロセスのハンドルを指定する。
DWORD dwAddr // SymLoadModule() を使ってロードしたモジュールのいずれかに含まれている有効な仮想アドレスを指定する。
);
DESC
指定されたアドレスを保持するモジュールのベースアドレスを取得する。
■ SymLoadModule
DWORD SymLoadModule(
HANDLE hProcess,
HANDLE hFile,
PSTR ImageName,
PSTR ModuleName,
DWORD BaseOfDll,
DWORD SizeOfDll
);
DESC
シンボルテーブルをロードします。
|
|
NINJAIDX 12