例外処理機構

Home > 2006-06 / CからC++へ > This Entry [com : 0][Tb : 0]

2006-06-12

比較的モダンなプログラミング言語の多くには、例外処理機構が備わっています。C++にも、やはり例外処理機構があります。このブログを始めた当初、例外処理に関する記事をいろいろと書きましたが、私は、C++とCの決定的な違いは例外処理機構の有無にあるのではないかとさえ考えています。

もちろん、何を以って「決定的な違い」とするのかにもよります。しかし、例外処理機構ほど、プログラミング・スタイルに大きな影響を与えるものはないと思うわけです。

例えば、クラスの機能は、扱いが面倒ではありますが、Cでも実現できないわけではありませんし、Cを使っていたとしても、オブジェクト指向に基づいた設計や実装を行うことは十分可能です。テンプレートをCで実現するのは大変ですが、なければないで済んでしまいます。

しかし、例外処理機構に関しては、言語の仕様や構造から見て、それを使わずに済ませようとすると、もはや標準C++とは別の(拡張EC++のような)言語になってしまうと思います。また、自分では例外処理機構を使っていないと思っていても、こっそりとそのためのコードが挿入されてしまうのも例外処理機構の特徴です。

それでは、例外処理機構がどんな機能なのかを見ていきましょう。基本的に、例外処理機構というのは、setjmpマクロとlongjmp関数による非局所分岐によく似ています。まずは構文からです。

try // try節
{
  // 通常の処理
}
catch (T& e) // catch節
{
  // 例外に対応する処理
}
catch (U& e)
{
  // 例外に対応する処理
}
catch (...)
{
  // 例外に対応する処理
}

上のような try〜catch で表される制御構造は監視ブロックと呼ばれます。try節に記述した処理を実行した結果として例外が送出されると、送出された例外の型と一致するものを、catch節で記述された宣言(上の例でいうと、T& eなど)から見つけ出します。

catch節は上のように1つ以上記述することができますので、最初に型が合致したところの処理が実行されます。もし、例外の型と一致するcatch節が見つからず、catch (...)があれば、その処理が実行されます。...はどんな型の例外でも捕捉するためのものです。

もし、catch節で例外が捕捉されなかった場合には、例外によってその関数は(例え中途半端な状態であったとしても)強制的に終了し、呼び出し元の関数に制御が移ります。呼び出し元では、例外を送出した関数がtry節にあれば、呼び出し元にあるcatch節から、例外の型に対応するものを見つけようとします。

このようにして、どこかのcatch節で例外が捕捉されるまで、どんどん呼び出し元に遡っていきます。そして、最後まで捕捉されなかった場合には、std::terminate関数が呼ばれます。

catch節での宣言についてですが、とりあえず例外オブジェクトは参照型で受け取るようにすべきです。詳しい理由はここでは書きませんが、そのように頭ごなしに覚えておいて、まず間違いはありません。

次に、例外を送出する方法ですが、これにはthrow式を使用します。

throw 右辺値式

throw式は、return文と似たような使い方をしますが、文ではなく、返却値型がvoidの式です。ですから、条件演算子の中など、他の式の部分式になることもできます。ここで、throw式に渡した右辺値式の型が例外の型となります。この型(またはその基底クラスの型)をcatch節から見つけ出そうとするわけです。

C++が標準でサポートする例外には、<signal.h>ヘッダで扱うシグナルのように非同期に発生するものはなく、ほとんどは文脈のどこかでthrow式によって送出されることになります。throw式によらないものとしては、dynamic_cast演算子やtypeid演算子によるものがありますが、ここでは詳しく触れません。

-- * -- * --

setjmp/longjmpとC++の例外を比べると、機能的な面だけを考えると、longjmp関数では整数値のみを情報として伝達できましたが、C++の例外はあらゆる型のオブジェクトを型情報とともに伝達することができます。また、非局所分岐の途中経路にある自動オブジェクトのデストラクタを呼び出すことができます。

機能以外の面を考えると、longjmp関数はライブラリの(どちらかといえばマイナーな)機能に過ぎず、普通の関数からlongjmp関数で抜け出すことは通常想定する必要がありません。しかし、C++ではほとんどの関数や演算子から例外が送出される可能性があるため、実行パスが複雑になるとともに、どこで例外が発生したとしても、リソース・リークや状態の矛盾を来たさないように細心の注意を払って、設計・実装を行わなければなりません。

Comment

Post a Comment









管理者にだけ表示を許可

Trackback

http://cppemb.blog17.fc2.com/tb.php/75-298cbc85

C++と組み込み環境 | Page Top▲

New >>
名前空間
<< old
new演算子とdelete演算子
ブログ内検索
RSSフィード