编译器是否为未使用的类生成虚函数表

Does compiler generate vtable for a class that is not used

本文关键字:函数 是否 未使用 编译器      更新时间:2023-10-16

你能解释一下编译器是否为一个有虚函数的类生成虚表,并且没有使用这个类(没有以任何形式创建的对象)。例如,

    class A {
          public:
           virtual void func() { }
    };
    int main()
    {
       return 0;
    }

对于上面的程序,编译器是否为类A创建虚变量表?这可能是一个重复的问题,但我想知道答案。如果它是重复的,请提供链接到来源。

我花了一些时间在gcc.godbolt.org服务上(非常感谢@RudolfsBundulis),尝试在什么情况下编译器会生成虚拟表,以满足我的好奇心。

class A {
    public:
        virtual void func() { }
};
class B : public A {
    public:
        void func() final override {};
};
int main()
{
   return 0;
}

任何抽象类的声明和实现都不会让编译器创建所有的东西(即使是这些类!)但是,这也取决于编译器的优化级别:

  1. -O1在任何编译器生成这样的main:

    int main()
    {
        A *a = new B;
        return 0;
    }
    
  2. -O2允许生成vtable和其他东西,但不适用任何编译器。我检查了最新的clang(3.6, 3.7)和gcc(4.9.2, 5.1.0),它只由gcc 4.9.2生成。

  3. -O3在clang (3.6, 3.7), gcc(5.1.0)上不生成任何东西。但是,它们会这样做,除非你有一个实际的调用:

    int main()
    {
        A *a = new B;
        a->func();
        return 0;
    }
    

    但请注意,gcc 4.9.2仍然生成它,即使-O3和没有调用a->func() !

所以,答案并没有改变@tenfour所说的-它确实依赖于编译器,取决于它的优化级别,甚至是编译器的版本。在这项研究中,真正有趣的是gcc 4.9.2仍然编译它,而不是真正需要的,尽管这种行为在gcc 5.1.0中被修复了。

虚值表的概念是一个实现细节,而不是c++标准的一部分。当编译器需要虚函数表时,就创建一个。

在您的示例中,该类永远不会被使用,并且编译器根本不会生成任何代码。

但是,即使您实例化类并调用具有副作用的函数,如果您从不使用需要虚参表的特性,则不需要生成虚参表。