请检查此代码..
class ex
{
int i;
public:
ex(int ii = 0):i(ii){}
~ex(){cout<<"dest"<<endl;}
void show()
{
cout<<"show fun called"<<endl;
}
};
int main(int argc , char *argv[])
{
ex *ob = NULL;
ob->show();
return 0;
}
当我们调用show方法时会发生什么。
谢谢..
答案 0 :(得分:3)
ex *ob = NULL;
ob->show();
您正在取消引用导致未定义行为的空指针。这很糟糕。
如果不清楚取消引用的位置,则了解->
运算符转换为
(*ob).show()
。
答案 1 :(得分:3)
这是未定义的行为。
话虽如此,在大多数编译器中,只要
,您就可以调用空指针上的方法。1)他们不会访问会员。
2)它们不是虚拟的。
大多数编译器都会翻译
ob->show()
到
call ob::show
这是应用程序空间中存在的有效方法。由于您没有访问成员,因此没有理由发生崩溃。
答案 2 :(得分:1)
在空指针指向的对象上调用show
方法被归类为“未定义的行为”,这意味着无论发生什么,你都无法判断C ++是错误的,因为你身边的错误。
未定义的行为意味着编译器编写者不需要关心编程错误的后果......所以他们可以自由地忽略这些情况。通常,未定义的行为被认为意味着“崩溃”,但这与事实相去甚远。执行具有未定义行为的代码可能崩溃,可能无所事事,可能显然什么都不做,让您的程序稍后在一个非常好的地方崩溃一百万条指令,甚至可能正在运行显然很好,没有崩溃,但默默地破坏你的数据。
C ++语言的一个主要假设是程序员不会搞错。在其他语言中,这不是真的,你会得到“运行时错误天使”,当你犯错误时会检查并停止你的程序......在C ++中,这些检查被认为太昂贵,因此你得到的不是“运行时错误天使” “未定义的行为守护进程”,如果出现错误,您将获得乐趣。
这增加了C ++的高度复杂性,我认为C ++对于初学者来说是一个非常糟糕的选择(初学者会犯很多错误),并且无法通过实验来学习C ++(因为错误的后果)是非确定性的。)
在你的特定情况下,鉴于编译器编写者是懒惰的(程序员的质量不是很差),我猜想在x86架构上代码不会造成任何损害,它可能会像指针一样执行到一个有效的对象。 这当然只是推测,因为它取决于编译器,硬件和编译器选项。可能有好的编译器有一个编译调试选项,会生成代码崩溃的代码。
答案 3 :(得分:0)
行为未定义。程序实际上的行为方式依赖于实现。我希望大多数实现尝试执行代码而不检查指针。所以你的初始例子应该顺利运行,因为它没有引用该类的任何本地成员。
检查以下代码的作用很有趣:
class ex
{
int i;
public:
ex(int ii = 0):i(ii){}
~ex(){cout<<"dest"<<endl;}
virtual void show()
{
cout<<"show fun called"<<endl;
}
};
int main(int argc , char *argv[])
{
ex *ob = NULL;
ob->show();
return 0;
}
如果方法是虚拟的,则运行时可能需要访问对象的某些本地数据,从而导致空指针或错误的地址异常。
修改强>
我在cygwin上使用GCC测试了以下略微修改的示例:
#include <iostream>
using namespace std;
class ex
{
int i;
public:
ex(int ii = 0):i(ii){}
~ex(){cout<<"dest"<<endl;}
void show()
{
cout<<"show fun called"<<endl;
}
virtual void vshow()
{
cout<<"vshow fun called"<<endl;
}
};
int main(int argc , char *argv[])
{
ex *ob = NULL;
ob->show();
ob->vshow();
return 0;
}
事实上,输出是:
show fun called
Segmentation fault (Core dumped)