1

私はboost::multi_index_container、オブジェクトのセットに対して複数のビューと並べ替え順序を提供するために使用しています。最近、(本質的に)すべてのオブジェクトの属性値を事前に計算し、これらの値を使用してそれらを並べ替えるカスタム並べ替え述語を使用してコンテナーを並べ替えたいと思いました(コード例については以下を参照)。

コンテナは正しくソートされますが、この述語を使用したソートは、オブジェクトの内部プロパティにoperator()アクセスするだけの述語を使用したソートよりもはるかに時間がかかることに気付きました。

さらに調査したところ、私の述語の(暗黙的に定義された)コピーコンストラクターが非常に頻繁に呼び出されたことがわかりました。述語の各コピーには完全な属性マップのコピーが含まれているため、これには長い時間がかかりました。

それ以来、オブジェクトに内部属性を追加することでこれを解決しましたが、これが最善の行動であるとはまだ確信していません。だから、私は知りたいです:

  • コピーコンストラクタがこれを頻繁に呼び出すのはなぜですか?
  • 述語を正しく定義していますか?述語にはこれほど多くの内部データが含まれるべきではありませんか?
  • さらに別の内部オブジェクト属性を定義するよりも良い解決策は何でしょうか?

これが私のコードの関連部分です。Objectその属性は問題に寄与しないため、クラスについてはあまり詳しく説明しませんでした。

class Predicate
{
public:
  Predicate()
  {
    // fill _attributes map with attribute values for all objects
  }

  bool operator()(const Object& a, const Object& b) const
  {
    std::map<Object, double>::const_iterator firstPos = _attributes.find( a );
    std::map<Object, double>::const_iterator secondPos = _attributes.find( b );

    // throw error if one of the objects could not be found

    return( firstPos->second < secondPos->second );
  }

private:
  std::map<Object, double> _attributes;
};

// Later, in order to sort the container
_container.sort( Predicate() );
4

3 に答える 3

2

1つの解決策は、述語の外部で属性マップを1回作成し、述語にconstマップへの参照を保持させることです。もう1つのオプションは、std::refまたはboost::refを述語に渡してソート関数に渡すことです。Predicateこれにより、のstd::mapデータメンバーの不要なコピーが回避されます。

Predicate p; // builds map internally
_container.sort( boost::ref(p) );
于 2012-09-12T08:05:41.970 に答える
2

比較オブジェクトがコピーされます。この状況は、C ++標準アルゴリズムを使用した状況を模倣しており、比較オブジェクトが参照によって取得されない理由があります。

boost::ref解決策は、以下と組み合わせて使用​​することboost::bindです。

#include <boost/bind.hpp>
#include <boost/ref.hpp>

...

Predicate p;
_container.sort(boost::bind<bool>(boost::ref(p),_1,_2));
于 2012-09-12T21:07:40.177 に答える
1

@Gnosophilon、理由は次のとおりです。関数オブジェクトは、非定数を持つことoperator()が許容されるようにC++によって定義されます。これにより、次のことが違法になります。

template<typename F>void call(const F& f){f();}

struct foo{void operator()(){}};

int main()
{
  call(foo());
}

foo()const参照としてキャプチャされ、constでfoo::operator()はないためです。さらに悪いことに、このような一時的なものfoo()は常にconstとしてキャプチャされるため、このオーバーロードを追加します

template<typename F>void call(F& f){f();}

どちらも動作しません。その場合の唯一の解決策は、値によるキャプチャです。これは、関数オブジェクトのコピーが安価であると想定しています。

C ++ 11では、これは右辺値参照で解決できた可能性がありますが、それでも問題は変わりません。

于 2012-09-13T20:13:57.470 に答える