C++ 带有typeid调用的UB

C++ 带有typeid调用的UB,c++,undefined-behavior,typeid,C++,Undefined Behavior,Typeid,我已经为理解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()" <&l

我已经为理解
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;
}
#包括
#包括
使用std::cout;
使用std::endl;
结构C;
结构B
{
长无符号整数散列;
B(C*C);
};
结构C:B
{
C():B(这个)
{

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

C()
    :            // 1
      B(this)    // 2
{                // 3
    ...
每个对象都应该有一些关于其typeinfo的信息,所以我们可以猜测构造函数是否初始化了它

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



(然而,VC++2013和g++4.8.3都给出了正确的结果。请注意,>o我不认为这是未定义的行为

前一句说

typeid
用于从构造函数调用的函数中时 …,如果
typedid
的操作数引用正在构造的对象…,
typeid
生成表示构造函数类的
std::type_info

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


B构造函数也在运行,但是
c
不是那里的“正在构造的对象”,所以你引用的句子不适用。

操作数的静态类型是
c
。构造函数的类是
B
c
不是
B
@MattMcNabb的基础哦,我的眼睛似乎有毛病:(让我想一想,我看不出你文章的第二部分是什么意思,我们正在查看的标准引用没有提到虚拟函数。(仅仅因为你没有虚拟函数的示例似乎有效,并不意味着它不可用)@Mattmcnab是的,即使没有虚拟函数,它仍然是UB。尽管如此,我解释了为什么我们得到了正确的结果。我的解释似乎不足以回答你的答案,但我想再问一个问题。如果我们将
typeid
替换为
dynamic\u cast
,行为是否会被低估?例如:(可能)最终编辑。请参见>oBut c的静态类型(又名
c
)不是
B
的基础。您可能没有正确理解我。我的意思是UB是在
C;
的构造过程中生成的,而
B
的构造函数是在
C
的构造过程中调用的。我相信我理解您。
C
不是B的构造函数中正在构造的对象,只是它的B-base sub-o对象是。我理解你的意思。但是“对象正在构造”是什么意思?我想它的意思是“在构造开始之后,但对象的生存期仍然不是”。因为B的构造函数是在
c
的构造过程中调用的,这意味着我们应用
typeid(c)
指向正在构造的对象。您能指出我在这方面的错误吗?使用的语言是“在构造函数或析构函数中…正在构造或销毁的对象”,这对我来说似乎很清楚。请注意,它是对象,而不是对象。在B的构造函数中,正在构造的对象是B的基本子对象;在C的构造函数中,正在构造的对象是
C
struct B
{
    long unsigned int hash;

    B(C *c);

    virtual ~B() = default; // here.
};