考虑这个例子:
#include <iostream>
class myclass
{
public:
void print() { std::cout << "myclass"; }
};
int main()
{
myclass* p = 0x0; // any address
p->print(); // prints "myclass"
}
我没有通过myclass类型的对象调用成员函数print
。相反,我从一个指向内存中随机位置的指针调用它。这是一个定义的行为吗?也就是说,成员函数是否保证在创建myclass
类型的任何对象之前执行?
答案 0 :(得分:11)
取消引用null(0)指针正在调用未定义的行为。该计划可以做任何喜欢的事情,包括按预期工作。
在某种程度上,你在这里得到它,因为print()
成员函数没有引用任何成员变量(没有任何成员变量),但编译器仍然可能生成会对你造成崩溃的代码。如果成员函数确实引用了任何成员变量,那么您将严重陷入未定义的行为。可能不值得尝试计算你可以做的事情的范围,因为你正在调用未定义的行为,这可能因编译器,编译器,版本,平台,平台,运行而异。
答案 1 :(得分:2)
您可能会发现更改print()
功能可能有助于启发这种情况:
void print() { std::cout << "myclass, this=" << this; }
这将输出C ++ this
指针的值,在您的示例中将为0
(或您设置p
的任何内容)。访问该类的任何数据成员将与解除引用this
相同,如果它不指向有效构造的myclass
实例,则会导致未定义的行为。
如果将函数声明为virtual
:
virtual void print() { std::cout << "myclass"; }
该实现可能在崩溃之前不会打印任何内容。原因是编译器生成代码以在调用虚拟函数时查看对象vtable
,以发现实际调用的函数。如果没有有效的对象,那很可能会崩溃。