3
A * a = new B();
a->foo();

B が A を派生させ、foo() が仮想関数であるとします。この例は非常に頻繁に発生します。問題は、コンパイラがこれをインライン化しようとしないと言われている場所があり、他の場所では正反対のことが述べられていることです。

個人的には、この呼び出しをインライン化できなかった理由はわかりません。コンパイル時に、どの関数が呼び出されているかを判断するのは非常に簡単だからです。

編集 1:「一般的なケース」を認識しており、コンパイラがインライン化するかどうかを決定するために多くの要因を考慮していることも認識しています。コンパイラがこの特定の呼び出しをインライン化する可能性があるかどうかを尋ねた場合、質問はおそらくより適切に形成されます。

私がこれを尋ねている理由は、 この C++ FAQからの次の特定の引用です。

オブジェクトがポインターまたは参照を介して参照される場合、仮想関数への呼び出しはインライン化できません。これは、呼び出しが動的に解決される必要があるためです。

4

4 に答える 4

2

明確にするために、g++ は明らかに仮想呼び出しの少なくともいくつかの些細なケースを正しくインライン化します。これはあなたのケースに似ていますが、より読みやすいアセンブラを得るために少し調整されています:)

void test(int);

class A { public: virtual int Bop() { return 1; } };

class B : public A { virtual int Bop() { return 4711; } };

int main() {
  A* a = new B();
  test(a->Bop());
}

$ g++ -O99 -S -c test.cpp

$ less test.s
...
main:
.LFB2:
    .cfi_startproc
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    movl    $8, %edi
    call    _Znwm
    movl    $4711, %edi            // hard coded 4711
    movq    $_ZTV1B+16, (%rax)
    call    _Z4testi               // calls test()
...
于 2013-06-28T11:02:44.540 に答える
0

コンパイラがインライン化することは期待できません。それは、コンパイラと選択された最適化レベル次第です。B::foo の実装が表示されていて、代入と呼び出しの間に何もしていないことを考えると、そうです、目視検査は、コンパイラがその最適化を行うのに十分な情報が利用可能であることを示唆しています。

しかし、そうする必要はありません。

また、他の多くの状況では、十分な情報が得られません。

于 2013-06-28T11:00:43.583 に答える