C++では、新しいエラー処理の方法として「例外(Exception)」が用意されています。
どのようなものなのか、例を書きながら説明します。
まずは、これまでの方法で作ったプログラムを作ってみましょう。
プロジェクトを作成し、cppファイルを1つだけ追加してください。
<sample program cpp080-01>
#include <iostream>
#include <fstream>
int main()
{
std::ifstream ifs;
ifs.open("Data.txt", std::ios::in);
if (!ifs) {
std::cout << "Open Error" << std::endl;
return 1;
}
ifs.close();
return 0;
}
|
<実行結果>
Open Error 続行するには何かキーを押してください・・・
わざとエラーを発生させていますので、「Data.txt」は作らないでください。
存在しないファイルをオープンし、エラーが発生したらメッセージを表示して異常終了しています。
上のプログラムを「例外」を使った方法に変えてみます。
<sample program cpp080-02>
#include <iostream>
#include <fstream>
int main()
{
std::ifstream ifs;
try {
ifs.open("Data.txt", std::ios::in);
if (!ifs) {
throw "Open Error";
}
}
catch (const char *pMessage) {
std::cout << pMessage << std::endl;
return 1;
}
ifs.close();
return 0;
}
|
<実行結果>
Open Error 続行するには何かキーを押してください・・・
実行結果は同じですが、かなり書き方が変わっています。
まず、「例外」を扱うには新しい命令を知る必要があります。
try {
//実行したいプログラム
}
catch(引数) {
//例外が発生した際に実行するプログラム
}
|
「try」は「試す」と言う意味ですよね。
「試しに」実行したいプログラムを動かしてみる、というイメージでしょうか。
「catch」は「捕まえる」と言う意味です。
何を「捕まえる」のかと言うと「例外」です。
これを説明するには、もう1つの命令を説明しなければなりません。
throw 例外; |
「throw」は「投げる」と言う意味です。
この命令が「例外」を投げ、「catch」で「捕まえる」のです。
「catch」の部分を見ると、
catch (const char *pMessage) {
std::cout << pMessage << std::endl;
return 1;
}
|
「引数」の部分が「char型のポインタ」になっています。
「char型のポインタ」は文字列を受け取る時によく使われます。
「throw」の部分を見ると、
if (!ifs) {
throw "Open Error";
}
|
エラーが発生した時に「文字列」を「投げて」います。
投げられた「文字列の例外」を受け取るため「catch」の引数は「char型のポインタ」になっているのです。
もちろん他の型でも大丈夫です。
これだけだと「前より面倒になったのでは・・・」と言うイメージかも知れません。
では、もう少し発展させてみましょう。
もう1度、これまでのエラー処理でプログラムを書いてみます。
<sample program cpp080-03>
#include <iostream>
#include <fstream>
#include <string>
bool FileOpen(std::ifstream &refInputFileStream, std::string strFilename);
int main()
{
std::ifstream ifs;
if (!FileOpen(ifs, "Data.txt")) {
std::cout << "Open Error" << std::endl;
return 1;
}
ifs.close();
return 0;
}
bool FileOpen(std::ifstream &refInputFileStream, std::string strFilename)
{
refInputFileStream.open(strFilename, std::ios::in);
if (!refInputFileStream) {
return false;
}
return true;
}
|
<実行結果>
Open Error 続行するには何かキーを押してください・・・
ファイルの読み込みを関数化して、エラーが発生した場合「bool型の戻り値」で分かるようになっています。
これまでも何度か書いてきたようなプログラムですね。
これを例外を使ったプログラムに変えてみます。
<sample program cpp080-04>
#include <iostream>
#include <fstream>
#include <string>
void FileOpen(std::ifstream &refInputFileStream, std::string strFilename);
int main()
{
std::ifstream ifs;
try {
FileOpen(ifs, "Data.txt");
}
catch (const char *pMessage) {
std::cout << pMessage << std::endl;
return 1;
}
ifs.close();
return 0;
}
void FileOpen(std::ifstream &refInputFileStream, std::string strFilename)
{
refInputFileStream.open(strFilename, std::ios::in);
if (!refInputFileStream) {
throw "Open Error";
}
}
|
<実行結果>
Open Error 続行するには何かキーを押してください・・・
関数内でエラーが発生した際に「throw」しています。
main関数の「try」の中には、関数呼び出しが書いてあります。
呼び出した関数内で発生したエラーをmain関数で「捕まえる」事が出来るのです。
これまでは「戻り値で成否を判断」していましたが、戻り値は必要無いため「void」になっています。
このように関数を超えて「例外」を「投げる」事が出来ます。
さらに、プログラムを発展させてみます。
<sample program cpp080-05>
#include <iostream>
#include <fstream>
#include <string>
void ReadData();
void FileOpen(std::ifstream &refInputFileStream, std::string strFilename);
int main()
{
try {
ReadData();
}
catch (const char *pMessage) {
std::cout << pMessage << std::endl;
return 1;
}
return 0;
}
void ReadData()
{
std::ifstream ifs;
FileOpen(ifs, "Data.txt");
ifs.close();
}
void FileOpen(std::ifstream &refInputFileStream, std::string strFilename)
{
refInputFileStream.open(strFilename, std::ios::in);
if (!refInputFileStream) {
throw "Open Error";
}
}
|
<実行結果>
Open Error 続行するには何かキーを押してください・・・
相変わらずmain関数に「try-catch」は書かれています。
「throw」はmain関数から呼ばれたReadData関数が呼んだFileOpen関数に書かれています。
main関数が直接呼び出していない関数でも、「try」の中に書かれた関数が呼び出した関数内で投げられた例外は「捕まえる」事が出来ます。
これを使う事で、戻り値を使う事無くエラー処理が可能になります。
また、エラー処理をまとめる事も出来るため、慣れれば非常に便利な考え方です。
最初は面倒かも知れませんが、色々と使ってみてください。