编译器什么时候可以静态绑定对虚函数的调用?

问题描述 投票:0回答:2

我希望如果类的类型在编译时已知,编译器能够静态解析对虚函数的函数调用(例如,如果类实例没有通过引用或指针使用,如情况 1 所示) ) 以下)。

但是,我观察到 Visual Studio 2010 的 C++ 编译器有一个奇怪的行为,我想知道当类的实例具有虚函数是通过引用访问的结构中的成员。

我是否应该期望编译器在下面的情况 2) 中静态绑定对 f() 的调用?即使

a
A
而不是
A&
,cr 的“引用”性是否以某种方式传播到 cr.a?

struct A
{
    virtual void f() ;
    virtual ~A() ;
};

struct B : A
{
    virtual void f() ;
    virtual ~B() ;
};

struct C {
    A a ;
    B b ;
};

C & GetACRef() ;

void test()
{
    // Case 1) The following calls to f() are statically bound i.e.
    // f() is called without looking up the virtual function ptr.
    C c ;  
    c.a.f() ;
    c.b.f() ;
    A a ;
    a.f() ;

    // Case 2) The following calls to f() go through the dynamic dispatching
    // virtual function lookup code. You can check if you generate the .asm
    // for this file.
    C & cr = GetACRef() ; // Note that C is not polymorphic
    cr.a.f() ; // visual C++ 2010 generates call to f using virtual dispatching
    cr.b.f() ; // visual C++ 2010 generates call to f using virtual dispatching  
}
c++ performance visual-studio-2010 polymorphism
2个回答
3
投票

显然编译器作者并没有费心去解决这个问题。也许它在实际代码中不够常见,不值得他们关注。

如果

GetACRef
在其他地方定义,也可能 C 在那里是多态的,这可能会影响优化。

请注意,编译器并没有解决所有可能的情况,即小型测试程序对人类来说是“显而易见的”。编译器关注的是大型实际程序中经常发生的情况。


2
投票

我不知道为什么 MSVC 不将您的“案例 2”场景编译为直接调用 - 这当然是可能的。我想只有微软才能回答。

请注意,GCC 确实会执行您正在寻找的优化(使用 MinGW 4.5.1 和

-O2
进行测试)。

此外,MSVC 即使对于以下序列也使用 vtable 调度(为了清楚起见 - 我正在使用

/Ox
优化选项):

A a;
A& ar(a);
ar.f();

因此,不需要函数或容器结构向编译器添加潜在的混乱层 - 编译器没有理由不能将

ar.f()
与该序列中的
a.f()
完全相同。 但正如博·佩尔森(Bo Persson)所建议的那样,也许这不是一个极其常见的优化场景(或者微软只是没有抽出时间来解决它)。同样,只有 MS 的编译器开发人员才能回答。

我不确定我是否会将这种行为归类为“奇怪” - 这是一个被错过的优化机会。我不确定这种事情有多常见。 在这种情况下,您是否应该期望编译器生成静态绑定调用? 或许。 但我认为它没有发生也不足为奇。

也许应该在 MS Connect 上提出问题。

© www.soinside.com 2019 - 2024. All rights reserved.