目次
低レイヤーのプログラミングとOS開発が趣味。C言語を使っています。
工作HardwareHubからのお知らせ
基本的な構文
#include <iostream>
#include <cstdlib>
using namespace std;
void MyFunc() {
if(true) {
throw "MyFunc";
}
// 正常時の処理...
}
int main() {
try {
if (true) { // エラー判定
throw "main";
// throw 1;
}
// 関数内からもthrowできます
MyFunc();
// 正常時の処理...
}
catch (const char* error) { // throwされた値
// エラー時の処理
// (↑tryでのみ有効なオブジェクトのデストラクタは、抜ける際に実行済みです)
cerr << "const char*: " << error << endl;
return EXIT_FAILURE;
}
catch (int error) { // intがthrowされた場合
try { // 入れ子にできます
if(true) {
throw "nested try-catch";
}
cerr << "int: " << error << endl;
return EXIT_FAILURE;
}
catch (const char* error) {
cerr << "const char*: " << error << endl;
return EXIT_FAILURE;
}
}
catch (...) { // 対応するcatchがないthrowの場合
return EXIT_FAILURE;
}
return 0;
}
例外指定子
#include <iostream>
#include <cstdlib>
using namespace std;
void MyFunc() throw() { // 例外指定 (← 実用性は低いですが知識として)
// MyFunc は例外を何も投げない throw() と宣言しているため
throw 1; // とするとエラーになります
}
int main() {
try {
MyFunc();
}
catch (...) {
return EXIT_FAILURE;
}
return 0;
}
catch節内でthrowする構文
異なる型の例外をthrowする可能性がある場合
#include <iostream>
using namespace std;
void MyFunc() {
try {
throw 1;
}
catch (int error) {
throw "MyFunc";
}
catch (const char* error) {
cerr << "同階層のものは実行されず" << endl;
}
}
int main() {
try {
MyFunc();
}
catch (const char* error) {
cerr << "1つ外のものが実行されます" << endl;
}
return 0;
}
同じ型の例外をthrowすることが確定している場合の特別構文
#include <iostream>
using namespace std;
void MyFunc() {
try {
throw "MyFunc";
// throw 1; // int型のthrow
}
catch (...) {
// どのような型のthrowであっても必ず行う必要のある
// 汎用性の高い処理を記述。メモリ解放など。
cerr << "caught at MyFunc" << endl;
throw; // exception rethrow (例外の再送出)
}
}
int main() {
try {
MyFunc();
}
catch (const char* error) {
cerr << "const char*: " << error << endl;
}
catch (int error) {
cerr << "int: " << error << endl;
}
return 0;
}
クラス型の例外をthrow
例外は基本型ではなくクラスにするのが通常です。その理解のためにはアップキャストの知識などが必要です。
#include <iostream>
#include <string>
#include <cstdlib>
class MyException {
public:
MyException(const char* error);
virtual ~MyException(); // 仮想デストラクタ
public:
const char* What() const;
protected:
std::string m_error;
};
class MySubException :
public MyException
{
public:
MySubException(const char* str);
};
using namespace std;
MyException::MyException(const char* error) :
m_error(error)
{
}
MyException::~MyException() {
}
const char* MyException::What() const {
return m_error.c_str();
}
MySubException::MySubException(const char* str) :
MyException("MySubException")
{
m_error += ": ";
m_error += str;
}
int main() {
try {
throw MySubException("main");
}
catch (const MyException& e) { // アップキャスト
cerr << e.What() << endl; //=> MySubException: main
return EXIT_FAILURE;
}
return 0;
}
コンストラクタで例外を投げる
#include <iostream>
#include <cstdlib>
using namespace std;
class MyClass {
public:
MyClass();
~MyClass();
};
MyClass::MyClass() {
cout << "MyClass::MyClass" << endl;
// メモリ確保 new していたとしても
throw exception();
// ↑標準例外クラスを使用しています
// - exception() すべての例外クラスの基底
// - logic_error() コンパイル時に検出可能な例外クラスの基底 (exception() の派生クラス)
// - invalid_argument() 不正な引数
// - ..等
// - runtime_error() 実行時に検出可能な例外クラスの基底 (exception() の派生クラス)
// - overflow_error() オーバーフロー
// - ..等
// - その他 (bad_*)
// - bad_alloc() メモリ確保に失敗
// - ..等
}
MyClass::~MyClass() {
// コンストラクタが完了する前に例外が投げられたため
// デストラクタは実行されない。つまり
// 解放 delete できない (メモリリークの原因の一つ)
cout << "MyClass::~MyClass" << endl;
}
int main() {
try {
MyClass obj; //=> MyClass::MyClass
// (MyClass::~MyClass は表示されない)
}
catch (...) {
return EXIT_FAILURE;
}
return 0;
}
デストラクタで例外を投げる
#include <iostream>
#include <cstdlib>
using namespace std;
class MyClass {
public:
MyClass();
~MyClass();
};
MyClass::MyClass() {
cout << "MyClass::MyClass" << endl;
}
MyClass::~MyClass() {
cout << "MyClass::~MyClass" << endl;
throw exception();
// デストラクタ内で例外が発生するような
// 操作を行うべきでない <*1↓>
// (発生してしまう場合でも以下のように
// デストラクタ内で処理することが必要です)
// try {
// throw exception();
// }
// catch (const exception& e) {
// // メモリ解放などの処理
// }
}
int main() {
try {
MyClass obj;
throw exception(); // ここで投げられた例外を処理して
}
catch (...) {
// ここに処理を移動させようとすると
// obj のデストラクタが実行されて
// 二重例外 (→エラーになります) が発生します <*1>
return EXIT_FAILURE;
}
return 0;
}
0
記事の執筆者にステッカーを贈る
有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。
さらに詳しく →Feedbacks
ログインするとコメントを投稿できます。
関連記事
- ダウンキャスト (C++をもう一度)実行時型情報 RTTI #include <iostream> #include <typeinfo> using namespace std; class MyClass { public: virtual ~MyClass() {} // typeid で正しい RTTI // (RunTime Type Information; 実行時型情報) ...
- 競技プログラミングの基本処理チートシート (C++)限られた時間の中で問題を解くために必要となる、競技プログラミングにおける基本的な処理のチートシートです。競プロにおけるメジャー言語 C++ を利用します。その際 C++11 の機能は利用せず C++03 の機能の範囲内で記述します。 頻度高く定期的に開催されるコンテスト AtCoder Codeforces main.cpp #include <iostream>
- 構造体と列挙体 (C++をもう一度)構造体 #include <iostream> using namespace std; struct MyStruct { char charval; int intval; }; void Show(MyStruct* obj) { cout << obj->intval << endl; } int main() { ...
- Valgrind による C/C++ メモリリーク検出JVM メモリリークでは JDK の jstat や jmap で原因を調査できます。C/C++ では valgrind の Memcheck ツールが利用できます。valgrind には複数のツールが含まれており既定のツールが Memcheck です。他のツールを利用する場合は --tool オプションで指定します。 [簡単な利用例](h
- クラスの基本/初期化 (C++をもう一度)構造体のように初期化する (非推奨) #include <iostream> using namespace std; const int MAX_STR = 16; class MyClass { public: int m_integer; char m_str[MAX_STR + 1]; void Show(); }; void MyClass::Show...