正如标题所说:
为什么在已删除指针上调用非虚拟成员函数是未定义的行为?
请注意,问题不会询问它是否是未定义的行为,而是询问为什么它是未定义的行为。
考虑以下程序:
#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
. 仅当this
在函数体内访问任何成员时才会取消引用。(即:在上面访问的示例中取消注释代码i
)
如果在函数中未访问成员,则上述代码实际上不应调用未定义的行为。
那么为什么标准要求通过删除的指针调用非虚成员函数是一种未定义的行为,而事实上它可以可靠地说取消引用this
应该是导致未定义行为的语句?仅仅是为了让语言的用户简单,标准只是对其进行概括,还是在这个任务中涉及一些更深层次的语义?
我的感觉是,也许因为它是实现定义了编译器如何调用成员函数,这可能是标准无法强制执行 UB 发生的实际点的原因。
有人可以确认吗?