2012-03-16 60 views
0

根据C++标准,这是完全可以接受的做到这一点:- 对空>操作对象

class P 
{ 
    void Method() {} 
}; 

... 

P* p = NULL; 
p->Method(); 

然而,这种轻微的变化:

class P 
{ 
    virtual void Method() {} 
}; 

... 

P* p = NULL; 
p->Method(); 

产生访问冲突时编译Visual Studio 2005.

据我所知,这是由微软的编译器实现中的一些怪癖造成的,而不是由于我完全无能为力造成的,所以问题是:

1)这种行为是否存在于更新版本的VS中?

2)有没有,我不知道,防止这种访问冲突的编译器设置?

+3

标准中的哪个位置可以使用? – 2012-03-16 14:00:01

回答

11

根据C++标准,这是完全可以接受这样做

不,它不是!
取消引用NULL指针是未定义的行为按照C++标准。 [#1]

但是,如果你不访问任何成员非虚成员函数里面极有可能在每个实施工作,因为非虚成员函数的this只需要derefernced访问成员this,因为没有成员在函数内部被访问因此结果。
但是,仅仅因为可观察的行为是好的并不意味着该程序是格式良好的 正确。
它仍然不合格。
然而这是一个无效的程序。

第二个版本崩溃,因为在访问虚拟成员函数时,即使调用相应的成员函数,即使在该成员函数内没有成员访问,也需要解引用this指针。

一个好的读:
What's the difference between how virtual and non-virtual member functions are called?


[#1]参考:

C++ 03标准:§1.9/ 4

Certa在本标准中描述的其他操作未定义(例如,取消引用null指针的效果)。 [注意:本国际标准对含有未定义行为的程序行为没有要求。 ]

+0

“如果你不访问函数内部的任何成员”*并且它不是虚拟*。换句话说,如果你不给编译器任何理由检查你所调用的指针,它可能不会注意到指针是NULL。 – ruakh 2012-03-16 13:56:05

+1

呵呵,毕竟这是我纯粹的无能,很高兴知道:) – obamator 2012-03-16 13:56:26

+0

该程序是格式良好的,因为它符合语法规则,可诊断语义规则和一个定义规则。 (被描述为导致未定义行为的规则明确地被排除在_diagnosable规则集之外。) – 2012-03-16 14:50:25

3

正如AI所说...我甚至会解释为什么:在许多C++实现中,this指针只是作为方法的第一个“隐藏”参数传递。所以,你看到了什么是

void Method() {} 

真的

void Method(P* this) {} 

但对于虚方法它更复杂。运行时需要访问指针来查找“真实”类型的P *,以便能够调用方法的“正确”虚拟实现。所以它就像

p->virtualTable->Method(p); 

所以总是使用p。

0

首先,任何人都不会编译,因为您已将Method定义为私有。

假设您将Method设为公共,您最终会遇到未定义的行为。基于典型的实现,大多数编译器将允许第一个“工作”(对于工作的相当松散的定义),而第二个将基本上总是失败。

这是因为非虚拟成员函数基本上是一个正常的函数,它接收一个额外的参数。在该函数内部,关键字this引用该额外参数,该参数是指向调用该函数的类实例的指针。如果您通过空指针调用成员函数,它通常意味着该函数this内部将是空指针。只要函数中没有任何内容试图取消引用this,那么您看到任何明显的副作用的机会都很大。

但是,虚拟函数基本上是一个通过指针调用的函数。在一个典型的实现中,任何具有一个或多个虚拟函数的类(无论是直接在该类中定义,还是从基类继承)都将有一个虚拟表。该类的每个实例(即每个对象)将包含一个指向其类的vtable的指针。当您尝试通过指针调用虚拟函数时,编译器将生成以下代码:

  1. 提领指针。
  2. 获取虚函数表的指针从该对象的适当偏移
  3. 取消引用虚函数表指针来获取类的虚函数表
  4. 着眼于V表相应的位置获得一个函数指针调用
  5. 调用该函数

给定一个空指针,该进程的第一步是将要中断。

我会注意到这个记录,这实际上适用于全部 C++编译器。 VC++在这方面远非独一无二。恰恰相反 - 虽然编译器在理论上可以实现与此不同的虚拟函数(举一个例子),但实际情况是,我所知道的每个编译器对于您发布的代码类型基本上都是相同的。事实上,所有C++编译器都会在给定相同代码的情况下显示类似的行为 - 实现中的主要差异大多是理论上的可能性,而不是您在实践中可能遇到的差异。