具有typeid调用的UB

UB with typeid invocation

本文关键字:UB 调用 typeid 具有      更新时间:2023-10-16

我已经为理解typeid运算符编写了代码。

#include <iostream>
#include <typeinfo>
using std::cout;
using std::endl;
struct C;
struct B
{
    long unsigned int hash;
    B(C *c);
};
struct C : B
{
    C() : B(this)
    {
        cout << "C()" << endl;
    }
};
B::B(C *c)
{
    hash = typeid(*c).hash_code(); //1, UB?
}
C c;
int main()
{
    cout << c.hash << endl;
    cout << typeid(c).hash_code() << endl;
}

我认为我编写的代码在//1产生UB,因为12.7/5表示

如果typeid的操作数引用了正在构造的对象,或者销毁,并且操作数的静态类型既不是构造函数或析构函数的类或其基之一,的结果typeid未定义

对吧?

我猜是UB。看看C的构造函数。

C()
    :            // 1
      B(this)    // 2
{                // 3
    ...

每个对象都应该有一些关于它的类型信息,所以我们可以猜测构造函数初始化它

正如您所知,标准为实现提供了很大的自由度。也许它并没有决定构造函数应该在// 1还是// 3中初始化typeinfo。如果一个实现决定在// 3中初始化它,您将得到错误的结果,因为typeinfo没有在// 2中初始化。


(然而,VC++2013和g++4.8.3都给出了正确的结果。请注意>o<)

我是对的。得到正确结果的原因是C没有虚函数 正如您所知,如果没有虚拟功能,RTTI就不会启用。所以编译器从静态类型生成了typeinfo,即C

通过虚拟函数,它生成UB的结果。

struct B
{
    long unsigned int hash;
    B(C *c);
    virtual ~B() = default; // here.
};

(实例)

我不认为这是未定义的行为。

上一句话说

typeid用于。。。一个名为…的函数。。。来自构造函数如果typedid的操作数指的是正在构造的对象。。。,CCD_ 12产生表示构造函数的类的CCD_。

正在构建的相关对象是c,而typeid的操作数的静态类型是C,因此结果是C的类型。

B构造函数也在运行,但c不是"正在构建的对象",因此您引用的句子不适用。