I had the following code in my program.
//Compare class
class SortByFutureVolume
{
public:
SortByFutureVolume(const Graph& _g): g(_g){}
bool operator() (const Index& lhs, const Index& rhs){
return g.getNode(lhs).futureVolume() > g.getNode(rhs).futureVolume();
}
private:
Graph g;
};
And then I use it for sorting like this:
std::sort(nodes.begin(), nodes.end(),SortByFutureVolume(g));
When I run the above code on my mac computer for a vector of size 23K it completes in a fraction of seconds. However, when I run on my ubuntu 14 machine. It takes several minutes and it hasn't even completed yet.
I search for this problem and found the following solution here Can I prevent std::sort from copying the passed comparison object
Basically modifying my code as so fixes the problem:
SortByFutureVolume s(g);
std::sort(_nodes.begin(), _nodes.begin()+ end, std::ref(s));
After this the runtime on both my mac an ubuntu are comparable. Very much faster.
I know that this works but I'm trying to understand why? I know that slow code above was due to copying of graph and SortByFutureVolume. Why do you need std::ref()? Is this solution even correct and is there a better way to do this?
Instead of having a Graph
data member in SortByFutureVolume
you should have a Graph &
or const Graph &
if g
can be read only. This way, anytime the SortByFutureVolume
is copied the Graph
is not copied.
class SortByFutureVolume
{
public:
SortByFutureVolume(const Graph& _g): g(_g){}
bool operator() (const Index& lhs, const Index& rhs){
return g.getNode(lhs).futureVolume() > g.getNode(rhs).futureVolume();
}
private:
Graph& g;
// or
const Graph& g;
};
As pointed out by Benjamin Lindley in the comments if You change SortByFutureVolume
to store a pointer to the Graph
instead of a refernece then SortByFutureVolume
becomes copy assignable as pointers can be assigned but references cannot. That would give you
class SortByFutureVolume
{
public:
SortByFutureVolume(const Graph& _g): g(&_g){}
bool operator() (const Index& lhs, const Index& rhs){
return g->getNode(lhs).futureVolume() > g->getNode(rhs).futureVolume();
}
private:
const Graph * g;
};
As a side not it is okay to have _g
as a variable name in a function parameter as it does not start with a capital letter but it is a good habit to not use leading underscores. This is doubly true in the global space where _g
would be an invalid identifier as it is reserved for the implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With