取消引用typeid中的空指针

时间:2011-05-17 08:52:37

标签: c++ typeid

在研究最近的一个问题时,我在'03标准[1]中找到了以下条款:

  

将typeid应用于左值时   表达式,其类型是多态的   类类型(10.3),结果参考   到表示的type_info对象   最派生对象的类型(1.8)   (也就是动态类型)   左值是指。如果是左值   表达式是通过应用   指针的一元*运算符和   指针是空指针值   (4.10),typeid表达式抛出   bad_typeid异常(18.5.3)。

具体来说,我想知道最后一位,它为解除引用空指针的结果提供了良好定义的行为。据我所知,这是唯一一次这样做[2]。具体来说,dynamic_cast<T&>对此案例没有特殊处理,这似乎是一个更有用的场景。因此,考虑dynamic_cast<T&>已被定义为在某些情况下抛出异常。

是否有特定原因使这种特殊表达得到特殊处理?它看起来完全是武断的,所以我猜它们有一些具体的用例。


[1]'11中存在类似的子句,但它引用了glvalue表达式,而不是左值表达式。

[2] delete 0;dynamic_cast<T*>(0)接近,但在这两种情况下,您都在处理指针值,而不是实际对象。

1 个答案:

答案 0 :(得分:4)

如果我更加关注下一个条款(5.2.8 / 3),我会看到这个

  

当typeid应用于   除了左值之外的表达式   多态类型,。 。 。表达是   没有评估。

换句话说,与sizeof一样(在C ++ 11中),编译器并不是要实际运行传递给typeid的代码,它只是应该分析它为了行为。不幸的是,与sizeof不同,由于多态类型,结果有时取决于表达式的运行时行为。

Base* p1 = new Derived;
Base* p2 = new Base;
typeid(*p1); //equivalent to typeid(Derived) [assuming Base is polymorphic]
typeid(*p2); //equivalent to typeid(Base)

如果表达式完全未被评估,则编译器无法检查RTTI以查看p1实际上是指向Derived而不是Base。然而,标准编写者决定更进一步,并声明如果表达式最终是指针类型的解引用,编译器应该只对其进行部分计算。如果指针为null,则抛出std::bad_typeid而不是执行取消引用并引入未定义的行为。

dynamic_cast对比。传递给dynamic_cast的表达式总是被完全评估,否则结果就没有意义了。由于编译器无论如何都需要完全评估表达式,因此指示它提前停止并抛出异常是没有意义的。

简而言之,对此进行特殊处理的方式与sizeof(*(int*)0)给予特殊处理的方式大致相同。 *(int*)0并不打算进行评估,所以没有理由首先引入未定义的行为,即使它看起来很糟糕。