我有一个排序列表,它将Comparator作为参数。在单元测试中,我尝试使用两种不同的比较器。
奇怪的是,使用StringReverseComparator
禁用两个if语句(已注释掉),一切正常,valgrind不会声明任何错误。
template<typename T> class Comparator {
public:
virtual int compare(const T * left, const T * right) = 0;
};
class StringReverseComparator : public Comparator<String> {
public:
int compare(const String *left, const String *right) {
int rv = strcasecmp((const char *)*left, (const char *)*right);
if (rv < 0) return 10;
if (rv > 0) return -10;
return rv;
}
};
class StringComparator : public Comparator<String> {
public:
int compare(const String *left, const String *right) {
return strcasecmp(left->operator const char*(), right->operator const char*());
}
};
一旦我启用了两个if语句,我就会从sort方法中获得段错误。 排序方法是sedgewick的标准qsort。
const char *
是来自String
类的运算符,用于访问字符数组。
首先我想,改变比较器可能会引起麻烦,所以我创建了一个新的排序列表实例。但是,只要我启用了两个if语句,它就会陷阱。
那么比较方法有什么问题?
//编辑:
好的,首先是排序代码(取自sedgewick):
template<typename T> class SortedList {
public:
// rest omitted
protected:
void sort() { qsort(0, _size - 1); }
void qsort(int left, int right) {
if (right > left) {
const T *v = _elements[right], *tmp;
int i = left-1;
int j = right;
for (;;) {
while (_comparator->compare(_elements[++i], v) < 0) ;
while (_comparator->compare(_elements[--j], v) > 0) ;
if (i >= j) break;
tmp = _elements[i];
_elements[i] = _elements[j];
_elements[j] = tmp;
}
tmp = _elements[i];
_elements[i] = _elements[right];
_elements[right] = tmp;
qsort(left, i-1);
qsort(i+1, right);
}
}
private:
int _size;
const T **_elements;
Comparator<T> *_comparator;
};
...这里是operator char *
。
顺便说一句:String类传递了所有单元测试,并且对valgrind也没问题。
class String {
public:
// rest omitted
operator const char * () const { return _s; }
const char * operator * () const { return _s; }
private:
char *_s;
};
关于strcasecmp
的用法:我的第一次尝试是:
return strcasecmp( ... ) * (-1);
使用与StringComparator
中相同的参数。当失败时,我尝试了任何我能想象到的东西,包括operator char *
的if语句和不同的调用语法。
strcasecmp
不会返回-1,0,1 - 正如许多教程中所提到的那样。返回值的大小和符号不同,在-1,0,1之后失败,我尝试使用10.值没有意义,可能是815或42,无论如何。
// edith 2
谢谢大家的关注!
我自己解决了。关键是,qsort算法不安全enuf :(
以下排序代码可以正常工作(使用任何类型的比较器):
void qsort(int left, int right) {
if (right > left) {
const T *v = _elements[right], *tmp;
int i = left-1;
int j = right;
for (;;) {
while (++i < _size && _comparator->compare(_elements[i], v) < 0) ;
while (--j > 0 && _comparator->compare(_elements[j], v) > 0) ;
if (i >= j) break;
tmp = _elements[i];
_elements[i] = _elements[j];
_elements[j] = tmp;
}
tmp = _elements[i];
_elements[i] = _elements[right];
_elements[right] = tmp;
qsort(left, i-1);
qsort(i+1, right);
}
}
感谢。