2011-11-19 7 views
13

は、一般的な統合機能を比較対値でファンクタのオブジェクトを渡す:参照することにより(C++)

template <class F> double integrate(F integrand); 

template <class F> double integrate(F& integrand); 

または

template <class F> double integrate(const F& integrand); 

でそれぞれの長所と短所は何ですか? STLは最初のアプローチ(値渡し)を使用します。最も普遍的な方法ですか?無料の関数名はL-することはできませんので、文脈を考慮

+0

STLは、参照のコンテナなどを使用するときに多くの問題が発生するため、通常は最初の方法を使用します。 –

+2

他の場所と同じです:「F」の内容によって、これらのバージョンは同じから非常に異なることがあります。 'F'がステートフルな場合、中間のバージョンだけが可能です。 –

+0

基本的には、あなたが選択したフォームに基づいてユーザーに要件を設定しています。価値のあるものであれば、あなたは完全性を失うことなくコピーすることができるファンクタを与えることを要求しています。参考にしていれば、あなたはあなたがそれを置いているどんなユーザーにも適した生涯をあなたに与えることを要求しています。 – Mordachai

答えて

19

関数オブジェクトは通常は小さくする必要があります。したがって、値渡しがパフォーマンスに顕著に影響するとは思いません(関数がその本体で行う作業と比較してください)。値によって渡すと、コード分析からも得ることができます。これは、by valueパラメーターが関数に対してローカルであり、オプティマイザーが、ファンクターのデータ・メンバーからのロードを省略することができるかどうかを通知する場合があるからです。

ファンクタがステートレスの場合、それを引数として渡すとコストはかかりません。ファンクタがとるパディングバイトは、(少なくともGCCで使用されるItanium Abiでは)特定の値を持つ必要はありません。参照を使用するときは、常にアドレスを渡す必要があります。

最後の1つ(const T&)は、C++ 03では、関数の型にconstを適用しようとすると、C++ 03ではプログラムが不正であるため、C++ 03では生の関数では機能しないという欠点があります。 (そしてSFINAEの場合です)。最近の実装では、関数型に適用すると、constは無視されます。

第2のもの(T&)には、一時的なファンクタを渡すことができないという明らかな欠点があります。

私は具体的なケースではっきりとした利点がない限り、私は一般的に値渡しします。

3

は、Fは「呼び出し可能オブジェクト」(free関数や演算子を持つクラスのようなもの()定義された)今

、であることが期待されます2番目のバージョンはそれには適していません。 3番目はF :: operator()がconstであることを前提としています(ただし、Fの状態を変更する必要がある場合はそうではありません) 最初のものは "独自のコピー"で動作しますが、

3つのうちのどれも「ユニバーサル」ではありませんが、最初のものは最も一般的なケースで動作する可能性が最も高いです。

5

STLは確か

(値渡し)最初のアプローチを使用して、標準ライブラリが値によってイテレータとファンクタを渡します。コピーが安価であると正しく(または間違って)仮定されています。これは、コピーにコストのかかるイテレータまたはファンクタを作成すると、あとで最適化する方法を見つけなければならない可能性があることを意味します。

しかし、標準ライブラリではファンクタを使用する目的のためだけです。ほとんどは述語ですが、std::transformなどもあります。関数を統合している場合は、何らかの数学ライブラリを示唆しています。その場合は、多くの状態を持つ関数を扱う可能性が非常に高いと思います。たとえば、非静的データメンバーとしてn + 1係数を持つn次多項式を表すクラスを持つことができます。

その場合は、const参照が良いかもしれません。そのようなファンクタをtransformのような標準的なアルゴリズムで使用する場合、ポインタを使って間接的に実行する小さなクラスにラップして、安価にコピーできるようにすることができます。

非const参照を取得すると、一時的に渡されるのを止めるため、ユーザーにとっては迷惑になる可能性があります。

関連する問題