2016-03-29 11 views
5

関数が引数として渡されたときにC++がinlineキーワードに従うかどうか疑問に思っています。次の例では、ループonFrameの新しいフレームをループのが呼び出されるたびにスタックにプッシュしますか?インライン関数を引数として渡す

bool interrupt = false; 

void run(std::function<void()> frame) { 
    while(!interrupt) frame(); 
} 

inline void onFrame() { 
    // do something each frame 
} 

int main() { 
    run(onFrame); 
} 

これに変更すると効果はありますか?

void run(std::function<inline void()> frame) { 
    while(!interrupt) frame(); 
} 

答えが確定していない場合は、これをテストする方法を見つける手助けができますか?メモリアドレスやデバッガを使用している可能性はありますか?

+1

[インラインでは、あなたが思うものではありません](http://stackoverflow.com/q/1759300/212858)。 – Useless

+0

関連:http://stackoverflow.com/questions/6451866/why-use-functors-over-functions – NathanOliver

+0

これはどういう意味ですか?インライン・キーワードの目的は、関数のインライン置換が関数呼び出しより優先されることをオプティマイザに示すインジケータとして機能することです。つまり、関数の本体に制御を移すためにコールCPU命令を実行する代わりに、 * "http://en.cppreference.com/w/cpp/language/inline –

答えて

3

はまだinlineキーワードに従う...新しいフレームだろう...スタックにプッシュすること

inlineキーワードが最初の場所で何をされていないこと(大規模なためthis questionを見ます参照)。バリーが行うように、あなたの関数呼び出し(運のためにもう一度:これはinlineキーワードとは何の関係もありません)をインライン化するオプティマイザを説得することを望んでいることを、仮定し


、関数テンプレート+ラムダは、おそらくです行く道。

は、なぜこれが、オプティマイザは、これらの各場合で作業しているかを検討し確認するには:

  1. 関数テンプレート+ラムダここ

    template <typename F> 
    void run(F frame) { while(!interrupt) frame(); } 
    
    // ... call site ... 
    run([]{ onFrame(); }); 
    

    、機能は全く存在します(テンプレートからインスタンス化されます)、コール・サイトでオプティマイザが有効であり、明確に定義されているすべてのものが必要です。オプティマイザはまだ合理的にそれが余分な命令キャッシュの圧力がスタックフレームの節約を上回るだろうと考えている場合

  2. 関数ポインタここ

    void run(void (*frame)()) { while(!interrupt) frame(); } 
    
    // ... call site ... 
    run(onFrame); 
    

    runが持っているかもしれ呼び出しをインライン化しないことも選択できます

    注意スタンドアローン関数としてコンパイルすることができます(ただし、誰もそれを使用していないことがわかると、そのコピーはリンカーによって破棄されることがあります)。特にアドレスが取られているので、onFrameでも同じです。最後に、オプティマイザは、多くの異なる関数ポインタでrunが呼び出されるかどうか、またはこれらの呼び出しをインライン化するかどうかを決定する際には1つのみを考慮する必要があります。全体として、それはより多くの作業のように思われ、リンク時の最適化として終わる可能性があります。

    NB。私はコンパイラがコード&のシンボルテーブルエントリを出すことを意味するために "スタンドアロン関数"を使用しました。

  3. std::function

    これは、すでに長い間なっています。レッツだけで、コンパイラからの情報を隠す意味し、機能の正確なタイプに依存し

    void run(std::function<void()> frame); 
    

    機能を作るために(型消去バリーが言及した)このクラスは偉大な長さに行くことではないに気づきますrunのコードを生成する点は、オプティマイザが動作することを意味しません(逆に、慎重な情報隠蔽をすべて元に戻すためにはもっと多くの作業が必要です)。あなたのオプティマイザが何テストについては


、あなたのプログラム全体の文脈でこれを検討する必要があります。それは、コードサイズと複雑さに応じて、異なるヒューリスティックを自由に選択できます。

が実際にとしたことを完全に確認するには、ソースを使って逆アセンブルするか、アセンブラにコンパイルしてください。 (はい、それは潜在的に大きな "正当な"ものですが、それはプラットフォーム固有のものであり、質問のためのトピックではなく、とにかく学習価値のあるスキルです)。

+0

しかしこれはどういう意味ですか?インライン・キーワードの目的は、関数のインライン置換が関数呼び出しより優先されることをオプティマイザに知らせることです。つまり、関数の本体に制御を移すためにコールCPU命令を実行する代わりに、関数本体は呼び出しを生成せずに実行されます。* "http://en.cppreference.com/w/cpp/language/inline –

+1

引用した直後の段落を読んでください。唯一の_binding_要件はリンケージであり、実際の呼び出しサイトのヒントに過ぎません。 – Useless

+0

ありがとうございました。私は「インライン」のキーワードが最初にやっていることではないということで問題があります。私は、コンパイラがその言語について一般的な記述をするのではなく、特定の方法でその機能を実装することを選択したことを説明するだけでいいと思っています。 –

8

std::functionのタイプ消去ディスパッチを経由しなければならない場合は、コンパイラがインライン展開するのはかなり難しいでしょう。それはとにかく起こる可能性がありますが、あなたはできるだけ固くしています。提案された代替案(std::function<inline void()>引数を取る)は不正です。

タイプ消去が必要ない場合は、タイプ消去を使用しないでください。 run()は、単に任意の呼び出し可能なを取ることができます:

template <class F> 
void run(F frame) { 
    while(!interrupt) frame(); 
} 

コンパイラのインライン化muuchが容易であること。ただ、inline関数を持つだけでは、関数がインライン化することは保証されません。 this answerを参照してください。

また、関数ポインタを渡していると、インラインになる可能性も低くなりますが、これは扱いにくいことに注意してください。私は偉大な例を持っていた、ここで答えを見つけようとしているが、インライン化は超重要であるならば、それまで、ラムダでそれをラップすることは行く方法かもしれ:

run([]{ onFrame(); }); 
0

コンパイルをリリースし、チェックのためにリストファイルを作成するか、デバッガで逆アセンブリを有効にします。知っている最善の方法は、生成されたコードをチェックすることです。

関連する問題