ショートカット
ファシリテーター × あり方
コーディングの向こう側
Hello, ANOTHER world!
オブジェクト指向のはなし
プログラミングのはなし
C言語実力診断クイズ
eSkillBooks
プログラミングのはなし

失敗しない関数をつくる

前のトピックでは、malloc() のエラーチェックに関する次のような例を取り上げました。そして、エラーチェックは絶対に省いてはいけないことを説明しました。

SAMPLE
CODE
int *pi = (int *)malloc( sizeof(int) );
if ( pi != 0 ) {
    // 通常処理
    *pi = 100;
}
else {
    // エラー処理
    ;
}

しかし、このようなエラーチェックを毎回書くのは面倒ですね。もう少し楽な方法はないでしょうか?

もしプログラム中のすべての場所で全く同じエラーチェックを行っているとしたら、もっと楽な方法があります。例えば個人で使用する目的でつくっているツールなら、メモリ不足で malloc がエラーを返した場合は単に異常終了すれば良いかも知れません。それなら次のようにできます。

SAMPLE
CODE
void *Storage( size_t sz )
{
    void *pv = malloc( sz );
    if ( pv == 0 ) {
       // エラー処理
        puts( "NO MEMORY!" );
        ABORT();
    }
    
    return pv;
}

void main()
{
    int *pi = (int *)Storage( sizeof(int) );
    *pi = 100;
}

上のように、エラーを返す関数をラッピングしてエラーを返さないようにできると便利です。ここでは malloc を Storage という名前の関数でラッピングしてエラーを返さないようにしています。もしメモリが不足して malloc が失敗した場合は Storage 関数の中で ABORT してしまいます。呼び出し側でのエラーチェックは不要になります。

もちろん、このような方法が使えるのは、プログラム全体で同じエラー処理を行う場合だけです。

このように、失敗しない関数を作ると便利な場合がよくあります。「失敗しない」というのは、呼び出し側が実行時エラーを考慮しなくて良いということです。呼び出された側は、何らかの実行時エラーが起こった場合には適切に対処し、呼び出し側に影響を及ぼさないよう設計しなければなりません。

上の例では、関数 Storage は malloc の実行時エラーの時には ABORT します。そのため、呼び出し側には常に 0 以外の価が返されます。したがって、呼び出し側では実行時エラーがないものと想定できるわけです。

(「プログラミングのはなし」は1998年1月から1999年1月にかけて作成されたコンテンツです。)