2006年02月13日

例外処理(リーブ)

つぎに例外処理を見ていきましょう。また、例外処理に関連して2フェーズコンストラクションについて見ていきたいと思います。このセクションをお読みになるにあたり、しつこいですが「携帯環境のリソースは非常に限られたものを想定している」というのを頭の片隅において置いてください。

 Series60では通常のC++によるtry-catch構文とは異なる例外処理の機構を利用します。これは通常のtry-catchによる例外処理が結果としてコードサイズの肥大化を招くためです。ですから、通常のtry-catchによる例外処理は採用されていません。

 そこで、try-catchの代用として出てくるのが「リーブ(Leave)」という考え方(機構、仕組みといっても良いかもしれません)です。リーブは、従来の例外と概念的にはほぼ同一です。以下にリーブについて概略をまとめます。

* C++の例外の代わりに使用される
* リソースエラー等が発生すると、コードはリーブする
* トラップハーネス(TRAPマクロやTRAPDマクロ)でリーブが処理されるまで関数のスタックをさかのぼる

リーブによる例外処理の例

 それでは、次のサンプルを見てみましょう(LeaveSample.zip)。このサンプルでは、メニューから「リーブのテスト」を選ぶと、意図的にメモリ不足のリーブが発生するようになってます。

// コード例(A)
void CLeaveSampleAppUi::HandleCommandL(TInt aCommand)
{
switch ( aCommand )
{
/// 中略….
case ELeaveSampleCmdAppTest:
{
// 次の関数の呼び出しはリーブを発生させる
this->iAppContainer->TestLeaveL();
break;
}
// 後は省略….

このTestLeaveL()関数の実装は次の通りです。

// コード例(B)
void CLeaveSampleContainer::TestLeaveL()
{
TInt reason = KErrNoMemory; // 勝手にメモリがないことにする
User::Leave(reason); // (1)例外を発生
this->iToDoLabel->SetTextL(_L("問題なく終了しました"));
// 上の一行は実行されない
}

 このサンプルでは、(1)においてメモリ不足のリーブを意図的に発生させています(User::Leave関数でリーブを発生)。このアプリケーションをそのまま実行すると次のような画面がでてきます。

それでは、このアプリケーションに対して例外処理のコードを加えたいと思います。上記コード例(A)を次のように書き換えてみてください。ボールドになっている箇所が書き換えた箇所です。

// コード例(C)
void CLeaveSampleAppUi::HandleCommandL(TInt aCommand)
{
switch ( aCommand )
{
/// 中略….
case ELeaveSampleCmdAppTest:
{
// TRAPDマクロで例外を捕捉
// error に例外コードが入ってくる
TRAPD( error,
this->iAppContainer->TestLeaveL(); );
if( error != KErrNone ){ // 例外が発生しているかを検査
this->iAppContainer->UpdateMessage();
}
break;
}
// 後は省略…

TRAPDマクロの第一引数にあるerrorに例外が発生した理由が格納されます。これをKErrorNone(つまり例外が発生しなかったことを表す)と比較しているわけです。

 もう少しリーブについて見ていきましょう。例外処理自体は、このような形で行うことができます。次に残る問題は「作成した関数、またはAPIで提供されている関数がリーブを発生させるか否か、コンパイラレベルでは判断できない」点にあります。リーブの機構はC++の言語ではなく、Series60で採用されているものです。つまり、例外を適切に処理するのであれば、先のコード例(A)を本来はコード例(C)のようにしなくてはいけません。しかし、コード例(A)のままでも問題なくコンパイルが可能ですし、警告も表示しません。

 そこで出てくるのが関数のコードコンベンションです。今回はコード例(B)で定義した関数は最後に「L」の付く関数になっていますが、一般にリーブを発生させる可能性のある関数はその名前の最後に「L」を付ける習慣になっています。このような「L」の付く関数に関しては(製品としてプログラムを出す場合は)必ずTRAPマクロや今回の様にTRAPDで処理をする必要があります。

補足:今回はリーブによる例外処理を見ていきましたが、一部のAPIには戻り値によって正常/異常終了を表すもあります。
posted by シンビアン at 20:40| Comment(0) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。