编译器何时可以将调用静态绑定到虚函数?

如果类的类型在编译时已知(例如,如果没有通过引用或指针使用类实例,如案例 1) 下面).

I expected the compiler to be able to statically resolve a function call to a virtual function if the type of the class is known at compile time (e.g. if the class instance is not being used through a reference or a pointer as illustrated in Case 1) below).

但是,我观察到 Visual Studio 2010 的 C++ 编译器有一个奇怪的行为,我想知道编译器是否有任何理由在类的实例时不将调用静态绑定到正确的"虚函数带有虚函数的是结构中的成员,通过引用访问.

However, I have observed a strange behavior with Visual Studio 2010's C++ compiler and I would like to know if there is any reason for the compiler not to statically bind the calls to the "right" virtual function when the instances of the classes with the virtual functions are members in a structure that is being accessed by reference.

我是否应该期望编译器在下面的情况 2) 中静态绑定对 f() 的调用?即使 aA 而不是 A&,cr 的引用"是否会以某种方式传播到 cr.a?

Should I expect the compiler to statically bind the calls to f() in Case 2) below? Is the "reference"ness of cr somehow propagating to cr.a even though a is an A and not an 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  
}

推荐答案

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

I don't know why MSVC doesn't compile your "Case 2" scenarios to direct calls - it's certainly possible. I think that only Microsoft would be able to answer.

请注意,GCC 确实执行了您正在寻找的优化(使用 MinGW 4.5.1 和 -O2 测试).

Note that GCC does perform the optimization that you're looking for (tested with MinGW 4.5.1 and -O2).

此外,MSVC 甚至在以下序列中也使用了 vtable 调度(为了清楚起见 - 我正在使用 /Ox 优化选项):

Also, MSVC used vtable dispatch even for the following sequence (for clarity - I'm using the /Ox optimization option):

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

因此,没有必要使用函数或容器结构为编译器添加潜在的混淆层 - 编译器没有理由不能将 ar.f() 完全相同>af() 在那个序列中.但正如 Bo Persson 所建议的那样,也许这不是一个非常常见的优化方案(或者 MS 根本没有解决它).同样,只有 MS 的编译器开发人员才能回答.

So there's no need for a function or container struct to add layers of potential confusion to the compiler - there's no reason the compiler can't treat ar.f() exactly the same as a.f() in that sequence. But as Bo Persson has suggested, perhaps it's not an extremely common optimization scenario (or MS have just plain not gotten around to it). Again, only the compiler devs at MS could answer.

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

I'm not sure I'd classify this behavior as 'strange' though - it's an optimization opportunity that's missed is all. I'm not sure how common this kind of thing might be. Should you expect the compiler to generate statically bound calls in this case? Maybe. But I think it's not too surprising that it doesn't happen.

也许应该在 MS Connect 上打开一个问题.

Maybe an issue should be opened on MS Connect.

相关文章