皆様、こんにちは。
高橋と申します。いつもお世話になっております。
環境は、Windows XP, VC ++ .NET 2003, コマンドコンソール(MFC + ATL)
で開発しております。
スレッドをいろいろ拝見してみると、STLなるものが
なにやら便利そうなので、試しに使用してみたのですが、
例外の件で、何を catch したらよいかがわからず
皆様の意見を拝借いたしたく、質問にまいった次第です。
以下で例外をキャッチできることは確認いたしました。
・・・(省略)
#include <vector>
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
// MFC を初期化して、エラーの場合は結果を印刷します。
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: 必要に応じてエラー コードを変更してください。
_tprintf(_T(致命的なエラー : MFC の初期化ができませんでし
た。\n));
return 1;
}
try{
vector<int> i(-1);
}
catch(logic_error e){
cout << e.what();
char c;
cin >> c;
}
return 0;
}
logic_error でキャッチしているのは、ソースを追ったところ
いろいろな例外クラスの親になっていたからなのですが、
この方法が一般的なのでしょうか?
なにげに例外の内容などもわかって(文字列でですが・・・)
catch(...){
}
とするより良いと思ったからなのですが、
実際の所は、どうなんでしょうか?
せっかくの例外なので、起こりうる全ての例外をもれなく catch して、
例外処理をした方が、正当なような気もするのですが・・・
なにぶん、STLなる物を初めて使用したもので、
見当違いのことを言っているかもしれませんが、
どうぞ、よろしくお願いいたします。
> logic_error でキャッチしているのは、ソースを追ったところ
> いろいろな例外クラスの親になっていたからなのですが、
> この方法が一般的なのでしょうか?
ここで実際に発生しているのはstd::length_errorです。
そして,std::length_errorはstd::logic_errorを継承しているため,
catchできているようです。
> とするより良いと思ったからなのですが、
> 実際の所は、どうなんでしょうか?
std::length_errorをcatchしたいのであれば,
catch (const std::length_error & e)
のように,リファレンスで受けるのが普通です。
#詳しくはMore Effective C++の項目13を参照のこと。
ちなみに,std::logic_errorやその基底クラスであるstd::
exceptionでcatchしたいのであれば,
絶対にリファレンスで受けなければいけません。
そうしないと,オブジェクトのslicingが起きて,
例えばwhatメンバ関数が使い物にならなくなります。
ちなみに,
try {
/* ... */
} catch (std::exception & e) {
std::cerr << std::exception::what : << e.what() << std::endl;
} catch (std::logic_error & e) {
std::cerr << std::logic_error::what : << e.what() << std::endl;
} catch (std::length_error & e) {
std::cerr << std::length_error::what : << e.what() << std::endl;
}
のように,基底クラスから書いていくと,
最初に基底クラスで引っかかります。
例外ハンドラは派生クラス側から書く必要があります。
#ちなみに,constに特別な意味はないです。
> せっかくの例外なので、起こりうる全ての例外をもれなく catch して、
> 例外処理をした方が、正当なような気もするのですが・・・
自分で処理できる例外はcatchして処理する,
自分で処理できない例外は放っておく,というのが例外処理の基本になると思います。
YuOさん、レスありがとうございます。
大変丁寧な回答ありがとうございました。
> catch (const std::length_error & e)
> のように,リファレンスで受けるのが普通です。
> #詳しくはMore Effective C++の項目13を参照のこと。
>
> ちなみに,std::logic_errorやその基底クラスであるstd::
> exceptionでcatchしたいのであれば,
> 絶対にリファレンスで受けなければいけません。
> そうしないと,オブジェクトのslicingが起きて,
> 例えばwhatメンバ関数が使い物にならなくなります。
なるほど、参照受けなんですか。
確かに、調べてみると exception に what が virtual
で定義されていているので、length_error のエラーメッセージが
消えちゃいますね。
コストの面から考えても、参照受けの方がいいようですね。
貴重なアドバイスありがとうございます。
> 自分で処理できる例外はcatchして処理する,
> 自分で処理できない例外は放っておく,というのが例外処理の基本になると思います
> 。
確かにそうですね、ずいぶん前に何かの本で読んだことがあるのですが、
忘れていました。(忘れやすい自分に反省します。)
しかし、STLは奥が深そう・・・
今日ちょっとSTLについて書かれたホームページを読んで、
使えるような気になっていたんですが、細かいところが
こうダメだと実践で使用するのは、まだ先になりそうです。
しかし、STLはちょっと触っただけでも有効性が理解できたので
(全てではありませんが・・・)
YuOさんが、ご紹介なさってくれた本などSTLについて書かれた本を探して、
自分でもう少し勉強してみます。
YuOさん、どうもありがとうございました。
例外処理と、STLについては、直接関係ないような・・・