Введение
В старом коде на Qt часто встречается функция qSort, а в современных примерах — std::sort. Что выбрать для сортировки в C++/Qt и почему код с qSort перестаёт собираться после перехода на Qt 6? В этой статье разберём вопрос std::sort vs qSort, разберём, как заменить все устаревшие алгоритмы Qt на стандартные, и покажем, на что обратить внимание при миграции.
Что такое qSort
В Qt 4 и Qt 5 был собственный набор алгоритмов в заголовке <QtAlgorithms>: qSort, qStableSort, qLowerBound, qBinaryFind, qFind, qCopy и другие. Их добавили в то время, когда стандартная библиотека C++ поддерживалась компиляторами по-разному. В Qt 5 эти функции объявили устаревшими и рекомендовали использовать алгоритмы STL. В Qt 6 их удалили окончательно.
std::sort vs qSort: сравнение
| std::sort | qSort | |
|---|---|---|
| Заголовок | <algorithm> | <QtAlgorithms> |
| Статус | Часть стандарта C++ | Устарел в Qt 5, удалён в Qt 6 |
| Контейнеры | Любые с итераторами произвольного доступа: std::vector, std::array, QList, массивы | Контейнеры Qt и STL |
| Сложность | Гарантированно O(n log n) с C++11 | O(n log n) в среднем |
| Стабильность | Нет (для стабильной — std::stable_sort) | Нет (для стабильной — qStableSort) |
| constexpr | С C++20 | Нет |
| Параллельная версия | С C++17 (политики выполнения) | Нет |
Пример: одна и та же сортировка
#include <QList>
#include <algorithm>
QList<int> list = {5, 3, 8, 1};
// Устаревший вариант (Qt 4/5)
// qSort(list.begin(), list.end());
// Современный вариант
std::sort(list.begin(), list.end()); // 1 3 5 8
Синтаксис почти не отличается, поэтому замена обычно сводится к поиску и замене по проекту.
Таблица замены устаревших алгоритмов Qt
| Устаревший Qt | Замена из STL |
|---|---|
| qSort(begin, end) | std::sort(begin, end) |
| qSort(container) | std::sort(container.begin(), container.end()) |
| qStableSort | std::stable_sort |
| qLess<T>() | std::less<T>() |
| qGreater<T>() | std::greater<T>() |
| qLowerBound / qUpperBound | std::lower_bound / std::upper_bound |
| qBinaryFind | std::lower_bound с проверкой результата |
| qFind | std::find |
| qCopy | std::copy |
| qFill | std::fill |
| qCount | std::count |
Обратите внимание на вариант qSort(container), принимавший контейнер целиком. У std::sort такой перегрузки нет, но в C++20 есть std::ranges::sort(container).
Сортировка по убыванию
#include <functional>
// Было
// qSort(list.begin(), list.end(), qGreater<int>());
// Стало
std::sort(list.begin(), list.end(), std::greater<int>());
// Или лямбдой
std::sort(list.begin(), list.end(), [](int a, int b) { return a > b; });
Как найти устаревший код в проекте
Компилятор поможет найти все проблемные места. Определите в файле проекта макрос, который превращает использование устаревших API в ошибки:
# qmake
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x050F00
# CMake
target_compile_definitions(myapp PRIVATE QT_DISABLE_DEPRECATED_BEFORE=0x050F00)
С этим макросом все функции, объявленные устаревшими до Qt 5.15, перестанут компилироваться ещё в Qt 5. Это удобный способ подготовить проект к переходу на Qt 6 заранее.
Что выбрать
- В новом коде используйте только std::sort и другие алгоритмы STL.
- Если важен порядок равных элементов, берите std::stable_sort.
- В старом проекте замените qSort до перехода на Qt 6: так миграция пройдёт спокойнее.
- Для C++20 и новее присмотритесь к
std::ranges::sortс проекциями.
Заключение
Выбор между std::sort и qSort сегодня очевиден: qSort удалён в Qt 6, а std::sort работает со всеми контейнерами Qt и даёт гарантированную производительность. Замена почти механическая и выполняется по таблице выше. Подробнее о возможностях стандартной сортировки читайте в статье Использование std::sort в C++, а о сортировке строк и структур в QList — в статье сортировка QList.