我正在使用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() );
答案 0 :(得分:2)
一种解决方案是在谓词之外构建属性映射一次,并使谓词保持对映射的const
引用。另一种选择是将std::ref
或boost::ref
传递给谓词到您的排序函数。这样可以避免不必要的Predicate
std::map
数据成员副本。
Predicate p; // builds map internally
_container.sort( boost::ref(p) );
答案 1 :(得分: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));
答案 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中,这可以通过右值引用来解决,但事情却保持不变。