2010-07-01

bad_array_new_lengthにまつわる不思議な文面

5.3.4 New [expr.new] paragraph 7

the new-expression terminates by throwing an exception of a type that would match a handler (15.3) of type std::bad_array_new_length (18.6.2.2).

"an exception of a type that would match a handler (15.3) of type"という文面が気になる。なぜこんな回りくどい書き方をしているのか。"throws std::bad_array_new_length"ではだめなのか。

bad_array_new_lengthというからには、public継承しているstd::bad_allocや、そのベースクラスであるstd::exceptionのハンドラーもマッチするはずである。さらには、catch(...)も、当然マッチするはずである。なぜこんな書き方なのか。

思うに、std::bad_array_new_lengthを継承した実装依存のクラスを投げる実装を許可するためではないだろうか。たとえば、

namespace std {

class implementation_defined_special_exception : public bad_array_new_length {
public:
implementation_defined_special_exception() throw();
};

}

このクラスは、bad_array_new_lengthのハンドラーにもマッチする。これを許可するために、わざとこのような周りくどい書き方をしているのではなかろうか。

本では、これを詳しく書く必要はないだろう。

ちなみに、VC10の<new>ヘッダーには、bad_array_new_lengthがある。それではと、さっそく試してみたところ、

#include <new>
int main()
{
    try {
// 現状の大半のWindows環境では失敗するはず
        std::size_t n = std::numeric_limits<std::size_t>::max() ;
        new int[n] ;
    }
    catch( std::bad_array_new_length )
    { std::cout << "bad_array_new_length" << std::endl ; }
    catch( std::bad_alloc )
    { std::cout << "bad_alloc" << std::endl ; }
}

Debug buildでは、allocation functionの内部で使っているmalloc()のassertマクロに引っかかり、例外を投げるまでもなくプログラムが終了した。まあ、Debug buildだ。それでもいいだろう。ではRelease buildではどうか。bad_allocの方のハンドラーにマッチした。

どうやら、単にヘッダーで定義されているだけのようだ。意味がない。

ところで、このコードを書いていて気がついたのだが、以下のコードをコンパイルすると、

struct B {} ;
struct D : B {} ;
int main()
{
    try { }
    catch(B){}
    catch(D){}
}

MSVCとGCCの両方で、「実際にDの例外が飛んできても、Bのハンドラーの方が優先されて、Dのハンドラーではキャッチでけへんねやけどええんか」という警告を出した。久しぶりに役に立つコンパイラの警告を見た気がする。

No comments: