として、タイトルは言う:
削除されたポインタで非仮想メンバー関数を呼び出すことが未定義の動作になるのはなぜですか?
質問は、それが未定義の動作であるかどうかを尋ねるのではなく、なぜそれが未定義の動作であるのかを尋ねることに注意してください。
次のプログラムを検討してください。
#include<iostream>
class Myclass
{
//int i
public:
void doSomething()
{
std::cout<<"Inside doSomething";
//i = 10;
}
};
int main()
{
Myclass *ptr = new Myclass;
delete ptr;
ptr->doSomething();
return 0;
}
this
上記のコードでは、コンパイラはメンバー関数の呼び出し中に実際には逆参照しませんdoSomething()
。関数は仮想関数ではなく、コンパイラーはこれを最初のパラメーターとして関数に渡すことにより、メンバー関数呼び出しを通常の関数呼び出しに変換することに注意してください(これは実装定義です)。コンパイラはコンパイル時に呼び出す関数を正確に決定できるため、これを行うことができます。したがって、実際には、削除されたポインターを介してメンバー関数を呼び出しても、は逆参照されませんthis
。関数本体内でメンバーがアクセスされた場合にのみ、this
が逆参照されます(つまり、アクセスする上記の例のコメント解除コードi
)
関数内でメンバーにアクセスしない場合、上記のコードが実際に未定義の動作を呼び出す必要はありません。
では、なぜ標準では、削除されたポインターを介して非仮想メンバー関数を呼び出すことが未定義の動作であると義務付けられているのに、実際には、間接参照this
が未定義の動作を引き起こすステートメントであると確実に言えるのでしょうか。標準が単にそれを一般化するのは、言語のユーザーにとって単純にするためだけですか、それともこのマンデートに関係するより深いセマンティクスがありますか?
おそらく、コンパイラがメンバー関数を呼び出す方法が実装で定義されているため、標準がUBが発生する実際のポイントを強制できない理由であると私は感じています。
誰かが確認できますか?