可能重复:
Why am I able to make a function call using an invalid class pointer
class B
{
public:
int i;
B():i(0){}
void func1()
{
cout<<“func1::B\n”;
}
void func2()
{
cout<<“i = “<<i;
}
};
int main()
{
B *bp = new B;
bp->func1();
delete bp;
bp = NULL;
bp->func1();
bp->func2();
return 1;
}
输出:
func1::B
func1::B
Runtime Exception:
NULL pointer access
答案 0 :(得分:7)
这是NULL
(或无效)对象指针的旧故事;对于标准,在NULL
对象指针上调用方法会导致未定义的行为,这意味着,就标准而言,它可以完美地工作,它可能会炸毁计算机或杀死一些随机的人
这里发生的是C ++编译器典型的类实现的结果:类通常实际上只包含字段的结构,所有方法实际上都是将this
指针作为隐藏参数的函数
现在,在这种实现中,如果您使用NULL
this
指针调用方法,如果它不访问任何字段,则实际上不会取消引用this
,所以它应该运行正常(与func1
)一样。
相反,如果该方法尝试访问任何字段(例如func2
),它将取消引用this
指针,NULL
将导致崩溃(取消引用NULL
指针,同样是未定义的行为,但通常会导致崩溃)。
请注意,如果您调用的方法是虚拟的,则几乎可以肯定使用NULL
this
指针调用它们会导致崩溃,因为虚拟调用是通过vtable解析的(一个函数指针数组),它隐藏在类的开头。
顺便说一句,void main()
不是标准的;它应该是int main()
(argv
和argc
是可选的。)
答案 1 :(得分:5)
当代码被修复为编译时,结果是合理预期的。
func1()
没有引用该类的任何成员,因此它没有发现它有一个空指针可以作为this
使用; func2()
确实引用this->i
,因此this
为空时失败。
严格来说,这是未定义的行为 - 任何事情都可能发生。但核心转储或运行时异常是对该特定错误的最常见响应之一。
答案 2 :(得分:1)
有什么好处的?第一个输出是正确的。第二个未定义的行为。第三种是尝试访问现在不存在的类中包含的信息。程序正确识别它是一个NULL指针。
答案 3 :(得分:0)
不是专家意见,只是看着这个:
bp-&gt; func1()不需要对类成员的任何访问 - 在Java中,这最好定义为静态。也许编译器正在内联函数?
答案 4 :(得分:0)
您正在删除bp,然后尝试从中调用,因为那里没有对象,实际上您已将引用设为null,因此存在运行时异常。
以这种方式思考:
你告诉编译器任何实例都不需要空间,因此当它尝试使用变量'i'时,它没有存储在任何有意义的地方并且程序失败。因为你已经将引用设为null,所以程序会在它执行此操作之前就将其捕获。
答案 5 :(得分:0)
我认为严格来说,第二次调用bp-&gt; func1()应该已经崩溃,但是通过输出它仍然使用已分配的bp调用(但现在是NULL),也许是一些错误的编译器优化(?) 。然后在bp-&gt; func1()调用内部它真的崩溃,因为成员i不可访问。
答案 6 :(得分:0)
从使用删除后使用指针的位置开始,输入“undefined behavior”land 。
因此,除此之外的任何行为都依赖于编译器实现,即使它“看起来有效”,也必须被认为是错误的。