4

ファンクタースタイルの述語の代わりに静的メンバー関数でテンプレートパラメーターを使用する場合、パフォーマンス上の利点はありますか?

たとえば、ファンクタースタイルのソートインターフェイスは通常、次のようなものです。

template <typename _Type, typename _Pred>
void sort (
    RandomAccessIterator first,
    RandomAccessIterator last ,
    _Pred less_than
    )
{
// actual sorting code here, calling less_than()...
}

このようなことを行うことができ_Pred、静的メンバー関数が含まれている必要があり_Pred::less_thanます。

template <typename _Type, typename _Pred>
void sort (
    RandomAccessIterator first,
    RandomAccessIterator last
    )
{
// actual sorting code here, calling _Pred::less_than()...
}

理論的には、最初のケースはヒープ上に一時的なファンクターオブジェクトを動的に作成する可能性がありますが、2番目のケースはコンパイル時に完全に評価されると思います。(たとえば)gccやmsvcは最適化に優れていることを理解していますが、最初のケースではこれを同じ程度に行うことができますか?

また、私はSTLソートルーチンなどを書き直そうとはしていません。より一般的なファンクターの質問の例にすぎません...

4

5 に答える 5

4

の通常の使用では、誰もまたはsortを呼び出さないという単純な理由で、ヒープに何も配置されません。述語がコンストラクターまたは比較のいずれかでまたはへの呼び出しを引き起こす場合、あなたは自分のせいにするだけです...mallocnewmallocnew

タイプのパラメーターにいくつかのスタックが使用される可能性があります(これは予約済みのシンボルであるため、コードで_Predテンプレートパラメーターを呼び出さないでください。の実装では呼び出すことができます)。ただし、述語オブジェクトが持つ可能性のあるデータメンバーに必要な作業以外に、関連する作業はありません。述部にデータメンバーがない場合、オプティマイザーにはフィールド日があり、データメンバーがある場合、静的メンバー関数はユーザーが実行したいことをサポートしません。_Pred_Predstd::sort

operator()述語が非仮想である限り、コンパイラーはそれsortを、定義を見ることができるかどうか、そしてそれが最良であると感じるかどうかのインスタンス化にインライン化できます。もちろん、何が高速であるかを保証するものではありませんが、静的メンバー関数の呼び出しが非仮想非静的メンバー関数の呼び出しよりも高速または低速であると考える理由はありません。列をなして。

于 2010-12-09T01:01:57.380 に答える
1

理論的には、最初のケースはヒープ上に一時的なファンクターオブジェクトを動的に作成する可能性がありますが、2番目のケースはコンパイル時に完全に評価されると思います。

最初のケースでは、スタック上に一時的なファンクターオブジェクトを作成します。Pred::Pred()ストレージを割り当てるかどうか心配していますか?その場合、静的関数が何らかの理由でヒープにストレージを割り当てるかどうかについても心配する必要があります。

とにかく、この種のイディオムで動作するほとんどの述語ファンクターオブジェクトは、オーバーロードされたを呼び出すことが唯一の目的であるため、非常に単純なコンストラクターを持っていますoperator ()。したがって、コンパイラーはオブジェクト構築を最適化し、単純な関数呼び出しを生成する可能性があります。

于 2010-12-09T00:56:41.980 に答える
0

最初のケースでは、

template<class T>
struct CompareByIntProperties {
    CompareByIntProperties(vector<T::*int> props) : props_(props) {}
    bool less_than(const T& a, const T& b) const {
        for (vector<T::*int>::const_iterator it = props_.begin();
             it != props_.end(); ++it) {
            if (a.(**it) < b.(**it)) return true;
            if (a.(**it) > b.(**it)) return false;
        }
        return false;
    }
    vector<T::*int> props_;
};

これにより、

vector<Foo::*int> properties;
if (compare_foo) properties.push_back(&Foo::foo);
if (compare_bar) properties.push_back(&Foo::bar);
if (compare_qux) properties.push_back(&Foo::qux);
sort(container.begin(), container.end(), CompareByIntProperties<Foo>(properties));

構文エラーはご容赦ください。コンパイルチェックは行われていません。しかし、あなたはその考えを理解します。

2番目のケースでは、静的メソッドを呼び出しているため、このようにコンパレータをカスタマイズするための自由な統治はありません。

効率は気になりません。非静的なものにアクセスしていない場合、優れたC ++コンパイラは、余分なオブジェクトの作成/破棄を排除し、場合によってはコンパレータをインライン化することさえできます。

于 2010-12-09T00:58:57.447 に答える
-1

仮想でない場合_Pred::less_than、コンパイラはそれがどの機能であるかを正確に認識しており、必要に応じてインライン化できるため、両方のソリューションは同一です。

それは私があなたのコードを正しく理解していることを前提としています-実際のコードはより明確になるでしょう。コード1はのようなことif (less_than.compare(a, b))をし、コード2はのようなことをすると思いif (_Pred::less_than(a, b))ます。

編集:例1はオブジェクトを値で渡すので、(コピーコンストラクターのように)必要なコストが発生することに注意してください。

于 2010-12-09T00:50:48.407 に答える
-1

もし私があなたなら、マイクロナノ秒をどちらか一方の方法で購入するかどうかについて心配するのをやめ、予約されている名前を使用しないことについてもっと心配します!

このようながらくたを心配する前に、あなたは長い道のりを歩んでいます。あなたがそこに着くまでに...うまくいけば、あなたはこのようながらくたを心配するのは無意味であることを学んだでしょう。

ただし、これを「答え」にするために、どちらも、プログラムの形式が正しくありません。

于 2010-12-09T00:55:06.620 に答える