4

性能上の理由から、仮想関数を避けるためにCuriously Reoccuring Template Patternを使用しています。何百万回も実行する小さなコマンドがたくさんあります。これをコマンドパターンに合わせようとしています。たくさんのコマンドをキューに追加し、それぞれを1つずつ実行しながら繰り返したいと思う。各コマンドは、CRTPを使用して仮想関数を回避します。私が取り組んでいる問題は、通常、コマンドパターンはポインタのベクトルを使って実装されているということです。しかし、Commandクラスがテンプレート化されると、ジェネリックコマンドポインタを渡すのが難しくなります。私はC++のエキスパートではないので、おそらくテンプレート化されたコマンドオブジェクトのベクトルを保存する明白な方法がありますか?そうCommand* commandは、コンパイルエラーを与え、問題はCommandがタイプではないです仮想関数のないコマンドパターン(C++)

boost:ptr_vector commands; 
AddCommand(Command* command) { 
    commands.push_back(command); 
} 

:私はのようなものを使用しようとしています。私はCommand<CommandType>を使用する必要がありますが、異なるタイプのコマンドを保持するためにキューが必要なので動作しません。

解決策はありますか?または、仮想関数は私の唯一のオプションですか?

ADDED:コマンドオブジェクトは、モンテカルロシミュレーションアルゴリズムの一部です。だから、Commandは正規分布からの乱数で、正規分布のパラメータはクラスの一部です。コマンドパターンは非常にきれいです。私は、特定の順序で、状態を維持する必要のある関数に多くの呼び出しを持っています。

+0

コマンドの例が参考になります。小さなコマンドテンプレートクラスがたくさんある場合、1または2を例として投稿すると、人々は代替案を提案するのに役立ちます。少なくとも、将来の読者のための質問の理解を向上させるでしょう。 –

+0

コマンドパターンを使用して解決している特定のシナリオに関するさらに詳しい情報を提供できますか?また、なぜ仮想関数が遅すぎると思うかを説明してください。あなたは仮想関数を使ってそれを実装しましたが、それは遅すぎると感じましたか? –

答えて

11

CRTPは、コンパイル時にオブジェクトの実行時の型を解決して、コンパイラが関数呼び出しをインライン化できるようにすることで、その魔法を実行します。ジェネリック型へのポインタのベクトルがある場合、コンパイラは特定の具体的な型を判別できず、コンパイル時の解決を行うことができません。

あなたの質問にある情報だけでは、仮想関数が最適な選択肢だと思います。しかし、仮想関数はそれほど遅くはありません。彼らはインライン関数よりも遅いですが、多くの場合、十分に速いです!特に、プロセスが処理時間の代わりにI/O時間によって制限されている場合。

One of the answers~this questionは、この問題についてさらに深く議論しています。要約すると、仮想関数呼び出しのオーバヘッドは、ナノ秒単位で測定される可能性があります。それよりも複雑ですが、ポイントは、あなたの関数が単一の割り当てのように本当に些細なことをしていない限り、仮想関数を恐れてはいけないということです。あなたはあなたの命令が小さかったと言ったので、そうかもしれません。私は、仮想関数を使って素早いプロトタイプを試して、それが許容できる性能を与えるかどうかを見てみたいと思います。

+0

私はそれをベンチマークしていないので、おそらくあなたは正しいです。単純な側面では、コマンドは乱数ジェネレータの呼び出しと同じように短いかもしれません。これらは文字通り非常にタイトなループで数百万回と呼ばれています。あなたは、仮想関数のオーバーヘッドが何であるかを推測できますか? – Tristan

+1

疑似乱数ジェネレータが単純な線形合同ジェネレータである場合は、重要な意味を持ちます。 Mersenne Twisterのような複雑なものの中には、仮想呼び出しのオーバーヘッドが重要ではないという十分な指示があるものがあります。 –

+0

コマンドメソッドとそれによって呼び出されるすべてのメソッドで非常に些細なことをしない限り、仮想メソッドの使用をお勧めします。あなたがコマンドメソッドのすべて/ほとんどで何かをやっているのなら、void *があなたの友人かもしれません。 – ConsultUtah

1

コンパイル時にコマンドキューを構築しているのでなければ、あなたが望むものは不可能です。

1

コマンドキューが頻繁に変更されるかどうかはわかりません。

実行頻度と比べてほとんど変化がない場合は、コード生成の仕事になると思われます。

必要なアクションを実行するプログラムを印刷して、&をオンザフライでリンクしてロードしてください。それは約1秒かかるはずです。クラス、オブジェクト、またはディスパッチはありません。シングルステップを実行すると、答えに重大な影響を与えないサイクルはほとんど見られません。