【发布时间】:2019-10-30 12:39:13
【问题描述】:
在以下问题中,其中一个答案表明对象的动态类型无法更改:When may the dynamic type of a referred to object change?
但是,我从 CPPCon 或其他会议上的一些演讲者那里听说这不是真的。
事实上,这似乎并不正确,因为 GCC 和 Clang 在以下示例的每次循环迭代中都会重新读取 vtable 指针:
class A {
public:
virtual int GetVal() const = 0;
};
int f(const A& a){
int sum = 0;
for (int i = 0; i < 10; ++i) {
// re-reads vtable pointer for every new call to GetVal
sum += a.GetVal();
}
return sum;
}
但是,如果添加以下内容:
class B final : public A {
public:
int GetVal() const override {
return 1;
}
};
int g(const B& b){
int sum = 0;
for (int i = 0; i < 10; ++i) {
sum += b.GetVal();
}
return sum;
}
然后函数g被简化为return 10;,这确实是意料之中的,因为final。它还表明,动态可能发生变化的唯一可能位置是 GetVal 内部。
我知道重新读取 vtable 指针很便宜,并且主要是因为纯粹的兴趣而询问。是什么禁用了此类编译器优化?
【问题讨论】:
-
C++ 中的对象没有“动态类型”——它们的类型在编译时是固定的。您可以通过指针或引用来引用对象,就好像它们是不同类型的一样,但对象的实际类型没有改变。
-
@NeilButterworth “如果某个左值表达式引用了多态对象,则其最衍生对象的类型称为动态类型。” en.cppreference.com/w/cpp/language/type
-
因为访问是通过指针。
-
I've heard that it is not true from some speaker on CPPCon添加相应演讲的链接会很有帮助,因为这样就可以告诉你这个人的意思。 -
关于以上评论交流;该标准在这里的术语很草率。在定义部分中,“动态类型”只为泛左值定义,而不是对象。然而,该标准确实在几个地方使用了未定义的术语“对象的动态类型”。其中一些用法可能意味着“glvalue 的动态类型”,但有些则不能。在其他情况下,也许它们的意思是“对象是其子对象的最派生对象”。
标签: c++ compiler-optimization lifetime virtual-functions vptr