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

一种解决方案是在谓词之外构建一次属性映射,并让谓词保存const对映射的引用。另一种选择是将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,原因是:函数对象是由 C++ 以operator()允许具有非常量的方式定义的。这将使以下内容非法:

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

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

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

因为foo()被捕获为 const 引用,foo::operator()而不是 const。更糟糕的是,临时的诸如foo()总是被捕获为 const,所以添加这个重载

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

也不会工作。唯一的解决方案是按值捕获,它假设函数对象的复制成本很低。

在 C++11 中,这可以通过右值引用来解决,但事情仍然保持不变。

于 2012-09-13T20:13:57.470 回答