我的程序中有以下代码。
//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;
};
然后我用它进行排序:
std::sort(nodes.begin(), nodes.end(),SortByFutureVolume(g));
当我在我的mac计算机上运行上面的代码以获得大小为23K的向量时,它会在几秒钟内完成。但是,当我在我的ubuntu 14机器上运行时。它需要几分钟而且还没有完成。
我搜索此问题并在此处找到以下解决方案Can I prevent std::sort from copying the passed comparison object
基本上修改我的代码就可以解决问题:
SortByFutureVolume s(g);
std::sort(_nodes.begin(), _nodes.begin()+ end, std::ref(s));
在此之后,我的mac和ubuntu上的运行时具有可比性。非常快。
我知道这有效,但我试图理解为什么?我知道上面的慢代码是由于复制了图形和SortByFutureVolume。你为什么需要std :: ref()?这个解决方案是否正确,是否有更好的方法来做到这一点?
答案 0 :(得分:4)
如果Graph
只能是SortByFutureVolume
,那么您应该拥有Graph &
或const Graph &
,而不是在g
中拥有SortByFutureVolume
数据成员。这样,只要复制Graph
,就不会复制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;
};
。
SortByFutureVolume
正如Benjamin Lindley在评论中指出的那样,如果您更改Graph
以存储指向SortByFutureVolume
的指针而不是参考,那么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;
};
将成为可分配的副本,因为指针可以被分配但参考不能。那会给你
_g
作为一方,不可以在函数参数中将_g
作为变量名称,因为它不以大写字母开头,但不使用前导下划线是一个好习惯。这在全球空间中是真实的,function ContestantInfoDropdown() {
var ContestantTest = ['Contestant 1', 'Contestant 2', 'Contestant 3', 'Contestant 4'];
var option = [];
for (var i=0;i<ContestantTest.length;i++){
option.push({value: ContestantTest[i] });
}
option.push({value: 'Contestant 5' });
return option
};
var createContestantsDropdownlist = ContestantInfoDropdown();
console.log(createContestantsDropdownlist);
将是一个无效的标识符,因为它是为实现保留的。
答案 1 :(得分:3)
std::ref
是伪装的指针。代码所做的是,它不是复制一个重量级SortByFutureVolume
对象,而是复制指向同一个对象的指针 - 这显然要快得多。
该选项可以在分拣机对象中进行Graph g
a(const)引用。
答案 2 :(得分:2)
每次复制时,SortByFutureVolume
都会复制整个图形,而std :: sort按比较函数对象的值执行大量复制。
见这里:
http://coliru.stacked-crooked.com/a/49b9cdad8eb3bc06
对于简单的std::vector<int>
排序,它在内部进行了SortByFutureVolume
类的20个实例化。您的图表可能被复制的次数相同。
std::ref
仅复制对比较函数对象的引用 - 这会删除所有深层副本,因此也可以加快整个过程。
答案 3 :(得分:2)
您正在调用的std :: sort变体的原型是
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );
(见http://en.cppreference.com/w/cpp/algorithm/sort)
编译器因此推断出当你传递一个不合格的SortByFutureVolume(g)
时,你正在传递值。使用您的SortByFutureVolume
定义构建临时文件需要图表的深层副本。然后可能会有第二个副本,因为临时值是按值传递的。如果此参数在sort中按值传递,则将进一步复制。
当你使用std::ref()
时,编译器可以推断出第三个参数是一个引用,因此传递成为引用,从而消除了图的二次副本。
正如其他人所指出的,解决方案是使成员g
成为引用,并通过引用使构造函数接受。
class SortByFutureVolume {
const Graph& g;
public:
SortByFutureVolume(const Graph& g_) : g(g_) {}
bool operator() (const Index& lhs, const Index& rhs){
return g.getNode(lhs).futureVolume() > g.getNode(rhs).futureVolume();
}
};
当然,如果你有一个C ++ 11兼容的编译器,你可以使用lambda:
std::sort(nodes.begin(), nodes.end(), [&g](const Index& lhs, const Index& rhs) {
return g.getNode(lhs).futureVolume() > g.getNode(rhs).futureVolume();
});