复制构造函数在boost :: multi_index_container中调用自定义排序谓词

时间:2012-09-12 07:58:18

标签: c++ boost copy-constructor boost-multi-index

我正在使用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() );

3 个答案:

答案 0 :(得分:2)

一种解决方案是在谓词之外构建属性映射一次,并使谓词保持对映射的const引用。另一种选择是将std::refboost::ref传递给谓词到您的排序函数。这样可以避免不必要的Predicate std::map数据成员副本。

Predicate p; // builds map internally
_container.sort( boost::ref(p) );

答案 1 :(得分:2)

比较对象被复制 - 这种情况模仿了使用C ++标准算法的算法,并且有理由说明我们不需要通过引用来获取比较对象。

解决方案是将boost::refboost::bind结合使用:

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

...

Predicate p;
_container.sort(boost::bind<bool>(boost::ref(p),_1,_2));

答案 2 :(得分:1)

@Gnosophilon,原因是:函数对象由C ++定义,允许使用非const 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中,这可以通过右值引用来解决,但事情却保持不变。