どちら(a)
と(b)
未定義の動作につながります。nullポインターを介してメンバー関数を呼び出すことは、常に未定義の動作です。関数が静的である場合、それは技術的にも未定義ですが、いくつかの論争があります。
最初に理解する必要があるのは、nullポインタを逆参照することが未定義の動作である理由です。C ++ 03では、実際には少し曖昧さが存在します。
が、「未定義の動作にヌルポインタ結果を参照解除」 §1.9/ 4および§8.3.2/ 4の両方でノートに記載されている、それが明示的に述べたことがないです。(注記は非規範的です。)
ただし、§3.10/ 2から推定することもできます。
左辺値はオブジェクトまたは関数を指します。
逆参照すると、結果は左辺値になります。nullポインタはオブジェクトを参照ため、左辺値を使用すると、未定義の動作が発生します。問題は、前の文が決して記述されていないことです。したがって、左辺値を「使用する」とはどういう意味ですか?それを生成するだけでいいですか、それとも左辺値から右辺値への変換を実行するというより正式な意味でそれを使うのですか?
いずれにせよ、右辺値に変換することはできません(§4.1/ 1)。
左辺値が参照するオブジェクトがT型のオブジェクトではなく、Tから派生した型のオブジェクトでもない場合、またはオブジェクトが初期化されていない場合、この変換を必要とするプログラムの動作は未定義です。
ここでは明らかに未定義の動作です。
あいまいさは、無効なポインタから値を参照するが使用しない(つまり、左辺値を取得するが右辺値に変換しない)ことが未定義の動作であるかどうかに起因します。そうでない場合は、int *i = 0; *i; &(*i);
明確です。これは活発な問題です。
したがって、厳密な「nullポインターの逆参照、未定義の動作の取得」ビューと、弱い「逆参照nullポインターの使用、未定義の動作の取得」ビューがあります。
今、私たちは質問を検討します。
はい、(a)
結果は未定義です。実際、this
がnullの場合、関数の内容に関係なく、結果は未定義です。
これは§5.2.5/ 3から続きます:
場合E1
種類有する「クラスXへのポインタを、」式はE1->E2
等価な形式に変換され(*(E1)).E2;
*(E1)
厳密な解釈で未定義の動作が発生し、.E2
それを右辺値に変換して、弱い解釈では未定義の動作にします。
また、(9.3.1 / 1)から直接定義されていない動作であることにも従います:
クラスXの非静的メンバー関数が、タイプX、またはXから派生したタイプではないオブジェクトに対して呼び出された場合、動作は未定義です。
静的関数では、厳密な解釈と弱い解釈が違いを生みます。厳密に言えば、未定義です。
静的メンバーは、クラスメンバーアクセス構文を使用して参照できます。その場合、object-expressionが評価されます。
つまり、静的ではないかのように評価され、もう一度nullポインターをで逆参照します(*(E1)).E2
。
ただし、E1
は静的メンバー関数呼び出しでは使用されないため、弱い解釈を使用すると、呼び出しは明確に定義されます。*(E1)
結果は左辺値になり、静的関数が解決されて*(E1)
破棄され、関数が呼び出されます。左辺値から右辺値への変換がないため、未定義の動作はありません。
C ++ 0xでは、n3126以降、あいまいさが残っています。とりあえず、安全に:厳密な解釈を使用してください。