Зачем в Qt используются собственные реализации стандартных функций и контейнеров?

Ответ

Qt предоставляет собственные классы (например, QString, QVector, QList) по нескольким ключевым причинам, связанным с историей, дизайном и кроссплатформенностью фреймворка.

Основные причины:

  1. Кроссплатформенность и согласованность: Qt был создан до широкого распространения стандартной библиотеки C++ (STL) и должен был работать на множестве платформ и компиляторов, где STL могла отсутствовать или вести себя по-разному. Собственные классы гарантируют идентичное поведение везде.
  2. Семантика копирования при записи (Copy-on-Write): Многие классы Qt, такие как QString или QByteArray, используют эту оптимизацию. Неглубокое копирование экономит память и повышает производительность, пока данные не будут изменены.
  3. Глубокая интеграция с экосистемой Qt: Эти классы спроектированы для совместной работы с механизмами Qt, такими как система мета-объектов (MOC), сигналы и слоты, а также моделью данных для QListView/QTableView. Например, QVariant может хранить любой тип Qt, что критично для property system.
  4. Расширенная функциональность: QString из коробки работает с Unicode (UTF-16), предоставляет удобные методы (split(), trimmed(), arg() для подстановки), чего не хватало std::string на момент создания Qt.
  5. Более безопасные итераторы: Qt предоставляет итераторы в стиле Java (QListIterator), которые могут быть безопаснее при модификации контейнера во время обхода, по сравнению с STL-итераторами.

Пример: Работа с QString vs std::string

// Qt-way: удобно и выразительно
QString path = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
QString filePath = QString("%1/report.txt").arg(path);

// STL-way: часто требует больше шаблонного кода
std::string path = getDocumentsPath(); // Нестандартная функция
std::string filePath = path + "/report.txt";

Когда что использовать? В чистом Qt-проекте использование Qt-классов упрощает разработку. В смешанных проектах (Qt + Boost/STL) часто приходится конвертировать типы, что может быть накладным. std::vector и другие STL-контейнеры можно использовать, но они не будут работать с некоторыми высокоуровневыми API Qt.

Ответ 18+ 🔞

А, ну это классика, ёпта! Сейчас объясню, почему в Qt эти свои тараканы в виде QString и QList завелись. История, блядь, древняя, как мир.

Представь себе: начало 90-х, стандартной библиотеки C++ толком нет, компиляторы на каждой платформе — отдельный адок, и тут норвежские чуваки затеяли писать фреймворк, который должен работать везде — от Windows до какого-нибудь встроенного железа. Какая, нахуй, STL? Её либо нет, либо она глючит по-разному. Вот и пришлось свои велосипеды изобретать, чтобы было одинаково и предсказуемо везде. Доверия ебать ноль было ко всему стороннему.

И знаешь, в чём главный прикол? Они не просто скопировали идеи, а сделали свои классы хитрыми жопами с кучей фишек:

  1. Копирование при записи (Copy-on-Write). Это гениальная штука, блядь! Ты копируешь QString — а по факту копируется только указатель на данные, пока ты не решишь что-то поменять. Памяти жрёт в разы меньше, а скорость — овердохуища. std::string так не умел долгие годы.
  2. Юникод из коробки. QString — это сразу UTF-16. В те времена с std::string и кодировками была такая жесть, что терпения ноль ебать. А тут всё готово: разделил, обрезал, подставил значения методом .arg() — красота!
  3. Всё завязано друг на друге. Экосистема Qt — это как хороший пазл. QVariant может завернуть в себя любой Qt-тип, чтобы работать со свойствами объектов или моделью в QTableView. Попробуй туда std::vector сунуть — получишь хуй с горы, ничего не заработает. Сигналы-слоты, MOC — всё это требует своих родных типов.

Вот смотри, как это выглядит на практике:

// Qt-способ: чисто, понятно, работает
QString docsPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
QString reportPath = QString("%1/отчёт.txt").arg(docsPath); // Красиво, да?

// STL-способ (условный): больше писанины, нужно всё самому
std::string docsPath = getDocsPathSomehow(); // А эту функцию ещё написать надо!
std::string reportPath = docsPath + "/отчёт.txt";

Так когда что использовать-то? Если пишешь на чистом Qt — используй Qt-классы, не мучайся. Жить будет проще. Если у тебя проект — пиздопроебина из Qt, Boost и STL, будь готов постоянно конвертировать .toStdString() и обратно, что, конечно, убьёт немного производительности. std::vector использовать можно, но стоит помнить: высокоуровневые штуки Qt его просто не поймут. В общем, ядраная вошь, но так исторически сложилось.