Возникли проблемы при использовании qSort - PullRequest
4 голосов
/ 18 ноября 2011

У меня есть этот код:

QVector<LogEvent *> currentItems;
//add a bunch of LogEvent objects to currentItems
qSort(currentItems.begin(), currentItems.end());

Это мой класс LogEvent:

LogEvent.h:

//LogEvent.h
class LogEvent : public QTreeWidgetItem {

public:
    LogEvent();
    LogEvent(QDateTime, LogEvent *parent = 0);
    ~LogEvent();

    bool operator<(const LogEvent *);
    bool operator>(const LogEvent *);
    bool operator<=(const LogEvent *);
    bool operator>=(const LogEvent *);
    bool operator==(const LogEvent *);

private:

    QDateTime timestamp;
};

LogEvent.cpp:

//LogEvent.cpp
LogEvent::LogEvent()
{

}

LogEvent::LogEvent(QDateTime timestamp, LogEvent *parent)
    : QTreeWidgetItem(parent)
{
    this->timestamp = timestamp;
}

bool LogEvent::operator<(const LogEvent * event) {
    return (this->timestamp < event->timestamp);
}

bool LogEvent::operator>(const LogEvent * event) {
    return (this->timestamp > event->timestamp);
}

bool LogEvent::operator<=(const LogEvent * event) {
    return (this->timestamp <= event->timestamp);
}

bool LogEvent::operator>=(const LogEvent * event) {
    return (this->timestamp >= event->timestamp);
}

bool LogEvent::operator==(const LogEvent * event) {
    return (this->timestamp == event->timestamp);
}

После выполнения сортировки объекты LogEvent в currentItems сортируются неправильно. Я почти уверен, что перегрузка моего оператора работает.

Когда я делаю такие вещи:

std::cout << currentItems[0]<=currentItems[1]?"T":"F";

будет выводить правильное значение.

Так что я делаю не так и как мне это исправить?

Ответы [ 4 ]

7 голосов
/ 18 ноября 2011

qСортировка сортирует указатели, а не объекты, на которые указывают эти указатели.Если вы хотите отсортировать LogEvents с помощью qSort, вам придется хранить их по значению, а не по ссылке (а также иметь операторы сравнения, которые принимают ссылку, qSort не найдет ваши функции сравнения с указателем) или передаст третьюаргумент с функцией, которую вы определяете.

Это может объяснить, почему это так с примерами.

LogEvent event1, event2;
LogEvent *eventptr1=&event1,*eventptr2=&event2;
event1<event2; // Operator not defined in your code
event1<eventptr2; // This will call the operator you have defined
eventptr1<eventptr2; // This will compare the pointers themselves, not the LogEvents. The pointers are not dereferenced here.

ETA: В интересах иметь один полный ответ для принятия, ясобираюсь оторвать несколько хороших битов из других ответов здесь.

Сначала определите стандартный синтаксис меньше оператора:

class LogEvent : public QTreeWidgetItem {

public:
  // ...
  bool operator<(const LogEvent *); // Non-standard, possibly reasonable for use in your own code.
  bool operator<(const LogEvent &); // Standard, will be used by most template algorithms.
  // ...
}

LogEvent.cpp

bool LogEvent::operator<(const LogEvent &event) {return timestamp<event.timestamp;}

Как только это будет сделано, вы можете использовать этот шаблон разыменования и сравнения из ответа Лима:

template<class T>
bool dereferencedLessThan(T * o1, T * o2) {
    return *o1 < *o2;
}

, чтобы отсортировать ваш список следующим образом:

QVector<LogEvent *> currentItems;
//add a bunch of LogEvent objects to currentItems
qSort(list.begin(), list.end(), dereferencedLessThan<LogEvent>);

Для полноты, он будетбыть хорошей формой, чтобы определить стандартные операторы сравнения синтаксиса для всех ваших сравнений.Держите ли вы нестандартные операторы сравнения на ваше усмотрение.

6 голосов
/ 19 ноября 2011

Вы можете определить функцию сравнения, используя два (общих) указателя:

template<class T>
bool dereferencedLessThan(T * o1, T * o2) {
    return *o1 < *o2;
}

А затем позвоните

void qSort (Начало RandomAccessIterator, конец RandomAccessIterator, LessThan lessThan)

как это:

qSort(list.begin(), list.end(), dereferencedLessThan<LogEvent>);

Затем этот метод можно использовать и для других типов без необходимости определения нескольких функций.

4 голосов
/ 18 ноября 2011

Разве операторы сравнения не должны брать константные ссылки, а не указатели?

В последнем фрагменте вы сравниваете адреса, а не значения.

0 голосов
/ 18 ноября 2011

Функция qSort требует, чтобы тип элемента (в приведенном выше примере, LogEvent) для реализации оператора <(). </em> Вот так:

bool LogEvent::operator<(const LogEvent& event) {
    return timestamp < event.timestamp;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...