通过这个问题,我也试图理解C ++的基础知识,因为我对C ++很新。排序矢量/自定义类列表(如this)的问题有很多很好的答案。在所有示例中,传递给sort的比较器函数的签名如下:
(const ClassType& obj1, const ClassType& obj2)
比较器功能必须使用此签名吗?或者我们也可以给出这样的东西:
(ClassType obj1, ClassType obj2)
假设我会相应地修改比较器的主体。
如果第一个签名是强制性的,那么为什么呢? 我想了解使用 const 和 reference'&'背后的原因。 我能想到的是 const 是因为你不希望比较器函数能够修改元素。引用是为了不创建多个副本。
如果我想对包含指向自定义类对象的指针的向量进行排序,我的签名应该如何?如(1)或(2)(见下文)或两者都有效? 要排序的vertor是vector类型
(1)
(const ClassType*& ptr1, const ClassType*& ptr2)
(2)
(ClassType* ptr1, ClassType* ptr2)
答案 0 :(得分:2)
我建议浏览This Documentation。
它解释了比较功能的签名必须等同于:
bool cmp(const Type1& a, const Type2& b);
然后更精确地继续解释每个参数需要是一个可隐式转换的类型,该对象是通过解除引用迭代器获得的对象。排序功能。
因此,如果你的迭代器是std::vector<ClassType*>::iterator
,那么你的参数需要隐式转换到ClassType*
。
如果您使用的内容相对较小,例如int
或pointer
,那么我会按价值接受它们:
bool cmp(ClassType* ptr1, ClassType* ptr2) // this is more efficient
答案 1 :(得分:1)
(ClassType obj1, ClassType obj2)
在大多数情况下,对于比较器,此签名也适用。不使用它的原因是因为你必须意识到这是通过值传递对象,这需要复制对象。
这将完全是浪费。比较器功能不需要拥有自己的参数副本。它需要的只是对需要比较的两个对象的引用,就是这样。此外,比较器功能不需要修改它正在比较的对象。它不应该这样做。因此,显式使用const引用会强制编译器发出编译错误,如果比较器函数被编码错误,则修改对象。
对于已删除复制构造函数的类,这种情况肯定不起作用的一种情况。根本无法复制这些类的实例。您仍然可以emplace
将它们放入容器中,但不能复制它们。但它们仍然可以比较。
答案 2 :(得分:0)
const是因为你知道在比较它们时不要更改值。参考是因为在您尝试比较它们时,您不想复制该值 - 它们甚至可能无法复制。
它应该看起来像你的第一个例子 - 它总是引用向量元素的const类型。
如果你有矢量,它总是:
T const & left, T const & right
因此,如果T是指针,那么比较的签名包括比较。
答案 3 :(得分:0)
STL并没有什么特别之处。我使用它有两个主要原因,作为一个稍微方便的数组(std :: vector),并且因为平衡的二叉搜索树是一个很难实现的。 STL具有比较器的标准签名,因此所有算法都被编写为在'&lt;'上运行操作(所以他们用if(!(a&lt; b || b&lt; a))来测试相等性)。他们可以很容易地选择'&gt;'操作或C qsort()约定,如果需要,您可以编写自己的模板化排序例程来执行此操作。但是,如果所有内容都使用相同的约定,那么使用C ++会更容易。
比较器采用const引用,因为比较器不应该修改它所比较的内容,因为引用对于对象比通过值更有效。如果你只想对整数进行排序(很少需要在实际程序中对原始整数进行排序,尽管它通常是作为练习完成的),你很可能编写自己的排序,它按值传递并且比STL快一点因此排序。