2011-08-26 17 views
2

皆さん、C++ - 関数のインライン展開ができないときは?

私が読んでいた「Thinking in C++"。 - 私はこの文に遭遇しました(CHAPインライン関数)を、

」 関数のアドレスが暗黙のうちに取られている場合、コンパイラはまた、インライン展開を行うことができませんか、明示的に」。

それは何を意味している 『』 taking address of function implicitly or explicitly
この場合にインライン化することはできませんなぜ?

ありがとうございます。

+3

機能が 'インライン化' されている場合は、そのアドレスはありますか? – Stan

答えて

4

実際、見積もりは誤解を招く可能性があります。

関数アドレスをとった場合、そのアドレスによる関数の実行は、命令ポインタを関数を記述するコードのブロックにジャンプさせることから成っているため、ライブラリ/実行可能ファイルで関数を生成する必要があります。

しかし、直接呼び出されたときにコンパイラが他の場所で関数をインライン化するのを確実に防ぐことはできません。

まず、レビュー:

// Explicit: 
void foo(); 

void (*func_ptr)() = foo; 


// Implicit 
struct Foo { virtual void bar() {} }; // address used in V-Table 

第二に、例をインライン化:

int main() { 
    (*func_ptr)(); // probably not inlined as the compiler can difficultly assert 
       // that nobody may modified it... since it's non-const. 

    foo(); // might be inlined 

    Foo f; 
    f.bar(); // might be inlined (the exact type of `f` is known) 
      // this is called, "devirtualizing" 

    Foo& g = accessSomeFoo(); 
    g.bar(); // probably not inlined unless the compiler can assert 
      // the type returned by accessSomeFoo 
      // (which requires knowing its definition) 
} 
5

機能のアドレスをとることは、assigning it to a function pointerを意味します。これは、リンクされた例のように明示的に起こり得る。私は、著者が「暗黙的に」何を意味するのかはわかりません。おそらく、関数を別の関数にパラメータとして渡すようなものです。

機能のアドレスを使用する場合は、最初にアドレスが必要です。インライン化は基本的には関数の呼び出しを基本的にその関数の呼び出しで置き換えることを意味するので、そのような変換の後に関数はそれ以上存在しないのでアドレスはありません - n呼び出し先の同じコード関数。したがって、関数のアドレスが何らかの方法で使用された場合、関数のアドレスはインライン化できません。

+2

まあ、理論的にはそうかもしれません。 'void foo(void);のようなコード。 void(* p)(void)= &foo; p(); '*はコンパイラによって最適化できます。 –

+0

+1 ..........短くて甘い答え: –

+0

これは、スピードの最適化を伴うコンパイラが関数ポインタを使って何もしないすべての行をインライン化するということですか? – TravisG

1

これが完全に正しいかどうかはわかりません。ただし、関数のアドレスを指定すると、その関数は関数のプリアンブルとクリーンアップコードを含むメモリ内に存在する必要があります。このプリアンブルとクリーンアップは、インライン展開時に省略されています。また、インライン化すると、最適化の可能性が最大限に高まります。

しかし、現代のコンパイラでは、インライン化が可能な場合でも、関数をインライン化できるはずです。考えてみましょう:

int compare (int a, int b) 
{ 
    return a compared to b 
} 

int main() 
{ 
    a = array of ints 

    qsort (a, compare); // take address of compare function, thus compare function exists in 
         // app as a proper function 

    compare (value1, value2); // there's no reason why this can't be inlined 
} 

私は引用符をインライン化できないかについて、より明確にするべきだと思う:

ポインタをインライン化できない機能を経由して呼び出される関数。

コンパイル時に、間接呼び出し(関数ポインタによる呼び出し)の時点でどの関数がインラインになるかを判断する方法がないためです。これは、関数ポインタによって指されている関数を直接呼び出された場所にインライン化することはできないと言っているわけではありません。

+0

あなたの答えの最後のビットは必ずしも真実ではありません。 @Peterの答えに対する私のコメントを見てください。 –

+0

@Oli:コンパイル時に推論できる関数ポインタは確かにインライン化することができると思いますが、なぜ誰かが関数ポインタを作成し、関数を割り当てる直接関数を呼び出すのではなく、間接的に呼び出すことができます。おそらくあなたがテンプレートを使用する場合。 – Skizz

+0

はい、テンプレートは良い例です。 –

関連する問題