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