I am using boost::multi_index_container to provide multiple views and sorting orders for a set of objects. Recently, I wanted to sort the container using a custom sorting predicate that (in essence) pre-calculates attribute values for all objects and then uses these values to sort them (see below for example code).
The container gets sorted correctly, but I noted that sorting with this predicate takes much longer that sorting with a predicate whose operator() simply accesses an internal property of my objects.
Further investigation showed that the (implicitly defined) copy-constructor of my predicate was called very often. Since each copy of the predicate contains a copy of the complete attribute map, this took a long time.
I have since solved this by adding an internal attribute to my objects, but I am still not convinced that this is the best of course of action. So, I would like to know:
- Why is the copy constructor called this often?
- Am I defining my predicate correctly? Are predicate not supposed to contain this much internal data?
- What would be a better solution than defining yet another internal object attribute?
Here’s the relevant portion of my code. I did not describe the Object class in much detail because its attributes do not contribute to the problem.
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() );
One solution would be to construct your attributes map once, outside of the predicate, and have the predicate hold a
constreference to the map. Another option would be to pass anstd::reforboost::refto the predicate to your sorting function. This will avoid unnecessary copies of thePredicate‘sstd::mapdata member.