Last Update 2023/12/20
概要
try、throw、catch 各ステートメントの動作確認
sample.cpp
#include <iostream>
struct Smpl { };
template<class T> void f(T x)
{
// tryステートメント
try
{
// throwステートメント
throw x;
}
catch (T) // 例外ハンドラ(型が一致した場合に処理)
{
// 本来はここで例外処理
std::cout << "catch : " << typeid(T).name() << std::endl;
}
}
int main()
{
Smpl s;
// 動作確認のため型引数を変えて関数テンプレートを呼び出し
f<int>(1);
f<double>(2.34);
f<const char *>("sample");
f<Smpl>(s);
f<long double>(1.23456789012345678L);
}
実行結果
$ gcc -Wall sample.cpp -lstdc++
$ ./a.out
catch : i
catch : d
catch : PKc
catch : 4Smpl
catch : e
(注) typeid(T).name()で出力される型を示す文字は実装依存
例外処理における例外オブジェクトの生成・破棄に関するテスト
sample.cpp
#include <iostream>
struct Smpl
{
// コンストラクタ
Smpl() { std::cout << "Constructor : " << this << std::endl; }
// コピーコンストラクタ
Smpl(const Smpl& rs) { std::cout << "Copy Constructor : " << this << std::endl; }
// デストラクタ
~Smpl() { std::cout << "Destructor : " << this << std::endl; }
};
struct Smpl2 : public Smpl {};
template<class T> void f(T& x)
{
try
{
std::cout << "[thorw s] start : " << &x << std::endl;
throw x;
std::cout << "[thorw s] end : " << &x << std::endl; // 実行されない
}
catch (const Smpl2 e)
{
std::cout << "[catch Smpl2] : " << &e << std::endl;
}
catch (const Smpl& e) // 参照によるキャッチ
{
std::cout << "[catch Smpl&] : " << &e << std::endl;
}
}
int main()
{
Smpl s1;
Smpl2 s2;
std::cout << std::endl;
f<Smpl>(s1);
std::cout << std::endl;
f<Smpl2>(s2);
std::cout << std::endl;
std::cout << "[main()] end" << std::endl;
}
実行結果
$ gcc -Wall sample.cpp -lstdc++
$ ./a.out
Constructor : 0x7ffe3e8360cf
Constructor : 0x7ffe3e8360ce
[thorw s] start : 0x7ffe3e8360cf
Copy Constructor : 0x1411340 <--- 例外オブジェクトをコピー初期化
[catch Smpl&] : 0x1411340 <--- スローされた例外オブジェクト
Destructor : 0x1411340 <--- 例外オブジェクトの破棄
[thorw s] start : 0x7ffe3e8360ce
Copy Constructor : 0x1411340 <--- 例外オブジェクトのコピー初期化
Copy Constructor : 0x7ffe3e836087 <--- 例外オブジェクトのコピーをコピー初期化
[catch Smpl2] : 0x7ffe3e836087 <--- スローされた例外オブジェクトのコピー
Destructor : 0x7ffe3e836087
Destructor : 0x1411340 <--- 例外オブジェクトの破棄
[main()] end
Destructor : 0x7ffe3e8360ce
Destructor : 0x7ffe3e8360cf
例外指定 noexcept を指定した関数を含むコードのコンパイル結果
sample.cpp
#include <iostream>
struct Smpl0
{
virtual void f1() noexcept;
virtual void f2();
virtual void f3() noexcept;
};
struct Smpl1 : public Smpl0
{
void f1() { throw 1; }; // 基底クラスでnoexcept指定で仮想関数を宣言
void f2() { throw 1; };
void f3() noexcept { std::cout << "Smpl1::f3()" << std::endl; } // 基底クラスでnoexcept指定で仮想関数を宣言
};
void f1() noexcept { std::cout << "f1()" << std::endl; } // noexcept指定され、例外のスロー無し
void f2() noexcept { std::cout << "f2()" << std::endl; throw 1; } // noexcept指定され、例外のスロー有り
void f3() { std::cout << "f3()" << std::endl; throw 1; } // noexcept指定無しで、例外のスロー有り
int main()
{
Smpl1 s1;
s1.f1();
f1();
f2();
f3();
}
実行結果
$ gcc -Wall sample.cpp -lstdc++
sample.cpp:12:14: error: looser exception specification on overriding virtual function ‘virtual void Smpl1::f1()’ <--- 例外指定の緩和に関するエラー
12 | void f1() { throw 1; }; // 基底クラスでnoexcept指定で仮想関数を宣言
| ^~
sample.cpp:5:22: note: overridden function is ‘virtual void Smpl0::f1() noexcept’
5 | virtual void f1() noexcept;
| ^~
sample.cpp: In function ‘void f2()’:
sample.cpp:18:56: warning: ‘throw’ will always call ‘terminate’ [-Wterminate]
18 | void f2() noexcept { std::cout << "f2()" << std::endl; throw 1; } // noexcept指定され、例外のスロー有り
実行環境
GNU bash, version 5.1.16
GCC-12.2.0
GNU C Library 2.36
GNU Binutils 2.39
GCC-12.2.0
GNU C Library 2.36
GNU Binutils 2.39
コード例・出力内容中の表記
・実行例中の太字表記部分は、コマンドなどの入力された文字列を示します。
・「︙」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。
・「︙」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。