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.
};