web-dev-qa-db-ja.com

コードがnullポインタを介して静的メソッドを明示的に呼び出すのはなぜですか?

私はいくつかの古いプロジェクトでこのようなコードを見てきました:

class Class {
    static void Method() {}
};

((Class*)0)->Method();

このコードには、nullポインターの逆参照が含まれているため、未定義の動作が含まれています(後で何が起こっても)。それは本当に意味がありません-キャストはコンパイラに型名を供給するためにあり、上記のコードを書いた人は誰でも代わりにこれを書くことができたでしょう:

Class::Method();

後者は大丈夫でしょう。

なぜ誰かが前のコードを書くのでしょうか?それは古き良き時代から知られているイディオムですか、それとも何ですか?

57
sharptooth

静的メンバー関数は、1989年にAT&T C++言語システム(標準化前)の リリース2. でC++に追加されました。それ以前は、staticキーワードを使用して静的メンバー関数を宣言できなかったため、コード作成者は回避策を使用しました。これは主に、nullポインターを間接化することで観察された回避策です。

Selected Readings AT&T C++言語システムのバージョン2.0に付随するセクション1-22で、Stroustrupは次のように書いています。

次のような移植性のないコードも観察されました。

_((X*)0)->f();
_

静的メンバー関数をシミュレートするために使用されました。遅かれ早かれ誰かがvirtualのように使用されるf()を作成し、アドレス0にXオブジェクトがないために呼び出しがひどく失敗するため、このトリックは時限爆弾です。 f()が仮想でない場合でも、ダイナミックリンクの一部の実装ではそのような呼び出しは失敗します。

あなたのコードは、Cfront 1.0でコンパイルするために、または静的メンバー関数が言語に追加されたときに気付いていなかった誰かによって書かれました。

staticによるメンバー関数の注釈は、Cheers andhthのように確かにパズルです。 --Alfが観察しました。 Cfront 1.0は、次のコードでそのコードを拒否します。

_error:  member Method() cannot be static
_

したがって、最初はそこにあったはずがありません。 Potatoswatterがおそらく正しいと思います。 staticは、C++ 2.0コンパイラが使用可能であることが保証された後、呼び出しコードが更新されることなく、Methodの静的メソッド属性を文書化して適用するために後日追加されました。これを確認するには、元のプログラマーにインタビューするか、少なくともソース管理履歴(存在する場合)を調べる必要があります。

67
ecatmur