【发布时间】:2012-12-10 08:27:51
【问题描述】:
正如标题所说:
为什么在删除的指针上调用非虚成员函数是未定义的行为?
请注意,问题不会询问它是否是未定义的行为,而是询问为什么这是未定义的行为。
#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;
}
在上面的代码中,编译器在调用成员函数doSomething()时实际上并没有取消引用this。请注意,该函数不是虚函数,编译器通过将 this 作为第一个参数传递给函数将成员函数调用转换为通常的函数调用(据我所知,这是实现定义的)。他们可以这样做,因为编译器可以准确地确定在编译时调用哪个函数。所以实际上,通过删除指针调用成员函数不会取消引用this。仅当在函数体内访问任何成员时,this 才会被取消引用。(即:在上面访问 i 的示例中取消注释代码)
如果在函数中未访问成员,则上述代码实际上不会调用未定义的行为。
那么为什么标准要求通过删除的指针调用非虚成员函数是未定义的行为,而事实上它可以可靠地说取消引用 this 应该是导致未定义行为的语句?仅仅是为了让语言的用户简单,标准只是对其进行概括,还是在这个任务中涉及一些更深层次的语义?
我的感觉是,也许因为它是实现定义了编译器如何调用成员函数,这可能是标准无法强制执行 UB 发生的实际点的原因。
有人可以确认吗?
【问题讨论】:
-
标准没有规定任何东西;这就是未定义行为的整个想法。说你声称它可以“可靠地说”的事情将是强制性的。
-
编译器永远不能“取消引用”任何东西。解引用是语言结构的一部分。它与代码生成无关。混淆语言和生成的代码是很危险的。该语言说调用成员函数会评估隐式实例参数,就是这样。
-
如果你想要你正在使用的行为,你应该使成员函数静态。当且仅当它不需要任何每个对象的状态时调用它在道德上是安全的,这意味着它应该是静态的。
标签: c++ undefined-behavior language-lawyer dereference