Kontenery STL czy Qt?

Jakie są plusy i minusy używania kontenerów Qt (QMap, QVector, itd.) nad ich odpowiednikiem STL?

Widzę jeden powód, dla którego warto wybrać Qt:

  • kontenery Qt mogą być przekazywane do innych części Qt. Na przykład mogą być używane do wypełniania QVariant, a następnie QSettings (z pewnymi ograniczeniami, tylko QList i QMap/QHash których klucze są ciągami są akceptowane).
Jest coś jeszcze?

Edit : zakładając, że aplikacja już opiera na Qt.

 169
Author: Julien-L, 2009-11-03

14 answers

Zacząłem od użycia STD::(w)string i kontenerów STL wyłącznie i konwersji do / Z odpowiedników Qt, ale już przełączyłem się na QString i okazało się, że używam kontenerów Qt coraz częściej.

Jeśli chodzi o ciągi, QString oferuje znacznie pełniejszą funkcjonalność w porównaniu do STD:: basic_string i jest całkowicie świadomy unicode. Oferuje również efektywne wdrożenie krów , na którym bardzo polegam.

Kontenery Qt:

  • oferują taką samą implementację COW jak w QString, co jest niezwykle przydatne, jeśli chodzi o użycie makra Qt foreach (który wykonuje kopię) oraz przy użyciu metatypów lub sygnałów i slotów.
  • może używać iteratorów w stylu stl lub iteratorów w stylu Java
  • można przesyłać strumieniowo za pomocą QDataStream
  • są szeroko stosowane w API Qt
  • mają stabilną implementację w systemach operacyjnych. Implementacja STL musi być zgodna ze standardem C++, ale jest w przeciwnym razie wolny, aby zrobić jak podoba mi się (zobacz kontrowersje std::string COW). Niektóre implementacje STL są szczególnie źle.
  • podaj skróty, które nie są dostępne, chyba że użyjesz TR1

QTL ma inną filozofię niż STL, którą dobrze podsumował J. Blanchette: "podczas gdy kontenery STL są zoptymalizowane pod kątem szybkości surowej, klasy kontenerów Qt zostały starannie zaprojektowane, aby zapewnić wygodę, Minimalne zużycie pamięci i minimalną ekspansję kodu."
Powyższy link zapewnia więcej szczegółów na temat implementacji QTL i stosowanych optymalizacji.

 123
Author: rpg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-03 10:11:31

Trudno odpowiedzieć na to pytanie. Może to naprawdę sprowadzać się do filozoficznego / subiektywnego argumentu.

To powiedziane...

Polecam zasadę " Kiedy w Rzymie... Czyń jak Rzymianie "

Co oznacza, że jeśli jesteś w Qt land, koduj tak jak Qt ' IANS. Nie dotyczy to tylko kwestii czytelności/spójności. Zastanów się, co się stanie, jeśli przechowasz wszystko w kontenerze stl, wtedy musisz przekazać wszystkie te dane do funkcji Qt. Czy naprawdę chcesz zarządzać kupa kodu, który kopiuje rzeczy do / Z kontenerów Qt. Twój kod jest już mocno zależny od Qt, więc to nie tak, że robisz go bardziej "standardowym" używając kontenerów stl. A jaki jest sens kontenera, Jeśli za każdym razem, gdy chcesz go użyć do czegoś użytecznego, musisz go skopiować do odpowiedniego kontenera Qt?

 167
Author: Doug T.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-03 16:45:59

Kontenery Qt są bardziej ograniczone niż kontenery STL. Na przykład, gdy STL są lepsze (wszystkie z nich trafiłem w przeszłości):

  • STL jest ustandaryzowany, nie zmienia się z każdą wersją Qt (Qt 2 miał QList (oparte na wskaźnikach) oraz QValueList (oparte na wartościach); Qt 3 miał QPtrList i QValueList; Qt 4 ma teraz QList, a to w ogóle nie przypomina QPtrList lub QValueList).
    Nawet jeśli w końcu użyjesz kontenerów Qt, użyj podzbioru API zgodnego ze STL (tj. push_back(), nie append(); front(), nie first(),..) aby uniknąć przenoszenia po raz kolejny Qt 5. Zarówno w przejściach Qt2->3, jak i Qt3->4 zmiany w kontenerach Qt należały do tych, które wymagały największej utraty kodu.
  • STL pojemniki dwukierunkowe wszystkie mają rbegin()/rend(), czyniąc iterację wsteczną symetryczną do iteracji do przodu. Nie wszystkie kontenery Qt je mają (asocjacyjne Nie), więc odwrotna iteracja jest niepotrzebnie skomplikowana.
  • kontenery STL mają zakres - insert() od różnych, ale kompatybilne, typy iteratorów, co sprawia, że std::copy() jest znacznie rzadziej potrzebne.
  • Kontenery STL mają argument szablonu Allocator, dzięki czemu zarządzanie pamięcią jest trywialne (wymagany typedef), w porównaniu z Qt (fork of QLineEdit wymagany dla s/QString/secqstring/). EDIT 20171220 : to odcina Qt od postępu w projektowaniu alokatorów po C++11 i C++17, por. np. rozmowa Johna Lakosa (część 2 ).
  • nie ma odpowiednika Qt std::deque.
  • std::list ma splice(). Ilekroć używam std::list, to dlatego, że potrzebuję splice().
  • std::stack, std::queue odpowiednio agregować ich podstawowy kontener i nie dziedziczyć go, ponieważ QStack, QQueue zrób.
  • QSet jest jak std::unordered_set, a nie jak std::set.
  • QList jest po prostu dziwne .

Wiele z powyższych rozwiązań można dość łatwo rozwiązać w Qt , ale biblioteka kontenerów w Qt wydaje się odczuwać brak obecnie skupiamy się na rozwoju.

edytuj 20150106: Po spędzeniu trochę czasu na próbach wprowadzenia obsługi C++11 do klas kontenerów Qt 5, zdecydowałem, że nie jest to warte tej pracy. Jeśli spojrzeć na pracę, która jest wprowadzana do implementacji bibliotek standardowych C++, jest całkiem jasne, że klasy Qt nigdy nie nadrobią zaległości. Wydaliśmy Qt 5.4 i QVector mimo to nie przenosi elementów na realokacje, nie posiada emplace_back() ani rvalue-push_back()... My również niedawno odrzucono szablon klasy QOptional, zamiast tego czekając na std::optional. Podobnie dla std::unique_ptr. Mam nadzieję, że ten trend się utrzyma.

 58
Author: Marc Mutz - mmutz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-20 13:10:55

Podzielmy te twierdzenia na rzeczywiste zjawiska mierzalne:

  • lżejszy: kontenery Qt zużywają mniej pamięci niż kontenery STL
  • bezpieczniejsze: kontenery Qt mają mniej możliwości niewłaściwego użycia
  • łatwiej: kontenery Qt stanowią mniejsze obciążenie intelektualne

Easier

Twierdzenie wysuwane w tym kontekście jest takie, że iteracja w stylu java jest w jakiś sposób "łatwiejsza" niż styl STL, a zatem Qt jest łatwiejsza w użyciu z powodu tego dodatkowego interfejs.

Style Java:

QListIterator<QString> i(list);
while (i.hasNext())
    qDebug() << i.next();

Styl STL:

QList<QString>::iterator i;
for (i = list.begin(); i != list.end(); ++i)
    qDebug << *i;

Styl Java iterator ma tę zaletę, że jest nieco mniejszy i czystszy. Problem w tym, że to już nie jest styl STL.

C++11 stl Style

for( auto i = list.begin(); i != list.end(); ++i)
    qDebug << *i;

Lub

C++11 foreach style

for (QString i : list)
    qDebug << i;

Co jest tak drastycznie proste, że nie ma powodu, aby kiedykolwiek używać czegokolwiek innego (chyba że nie obsługujesz C++11).

Moim ulubionym jest jednak:

BOOST_FOREACH(QString i, list)
{
    qDebug << i;
}

Więc, jak możemy widzisz, ten interfejs zyskuje nam nic oprócz dodatkowego interfejsu, na szczycie już eleganckiego, opływowego i nowoczesnego interfejsu. Dodanie niepotrzebnego poziomu abstrakcji na już stabilnym i użytecznym interfejsie? To nie mój pomysł na "łatwiejsze".

Ponadto Interfejsy Qt foreach i java dodają narzuty; kopiują strukturę i zapewniają niepotrzebny poziom indrection. To może nie wydawać się zbyt wiele, ale po co dodawać warstwę nad głową, aby zapewnić nie-że-dużo-prostszy interfejs? Java ma ten interfejs, ponieważ java nie ma przeciążenia operatora; C++ tak.

Bezpieczniej

Uzasadnienie, jakie daje Qt, to ukryty problem dzielenia, który nie jest ani Ukryty, ani problemem. Wiąże się to jednak z dzieleniem się.

QVector<int> a, b;
a.resize(100000); // make a big vector filled with 0.

QVector<int>::iterator i = a.begin();
// WRONG way of using the iterator i:
b = a;
/*
Now we should be careful with iterator i since it will point to shared data
If we do *i = 4 then we would change the shared instance (both vectors)
The behavior differs from STL containers. Avoid doing such things in Qt.
*/

Po pierwsze, nie jest to dorozumiane; wyraźnie przypisujesz jeden wektor do drugiego. Specyfikacja iteratora STL wyraźnie wskazuje, że Iteratory należą do kontenera, więc wyraźnie Wprowadziliśmy wspólny kontener między b a. po drugie, nie stanowi to problemu; dopóki przestrzegane są wszystkie zasady specyfikacji iteratora, absolutnie nic nie pójdzie źle. Jedyny raz, kiedy coś pójdzie nie tak jest tutaj:

b.clear(); // Now the iterator i is completely invalid.

Qt określa to tak, jakby to coś znaczyło, jakby problem powstał de novo z tego scenariusza. Iterator jest unieważniony i tak jak wszystko, do czego można uzyskać dostęp z wielu obszarów, tak to działa. W rzeczywistości będzie to możliwe dzięki iteratorom w stylu Java w Qt, dzięki dużej zależności od niejawnego udostępniania, które jest antypaternem, jak udokumentowano tutaj , i w wielu innych obszarach . Wydaje się to szczególnie dziwne, że ta "optymalizacja" jest wykorzystywana w ramach, które coraz bardziej podążają w kierunku wielowątkowości, ale to jest marketing dla Ciebie.

Zapalniczka

Ta jest trochę trudniejsza. Korzystanie z Copy-On-Write i ukrytych strategii udostępniania i wzrostu sprawia, że bardzo trudno jest faktycznie zagwarantować o tym, ile pamięci będzie zużywał kontener w danym momencie. Jest to w przeciwieństwie do STL, który daje silne Gwarancje algorytmiczne.

Wiemy, że minimalna granica zmarnowanej przestrzeni dla wektora jest pierwiastkiem kwadratowym długości wektora , ale wydaje się, że nie ma sposobu na zaimplementowanie tego w Qt; różne "optymalizacje", które wspierają, wykluczałyby tę bardzo ważną funkcję oszczędzania przestrzeni. STL nie wymaga tej funkcji (a większość korzysta z podwojenia wzrostu, co jest bardziej marnotrawstwo), ale ważne jest, aby pamiętać, że możesz przynajmniej zaimplementować tę funkcję, jeśli zajdzie taka potrzeba.

To samo dotyczy podwójnie połączonych list, które mogłyby użyć linkowania XOr, aby drastycznie zmniejszyć przestrzeń używaną. Ponownie, jest to niemożliwe z Qt, ze względu na jego wymagania dotyczące wzrostu i krów.

COW może rzeczywiście zrobić coś lżejszego, ale tak samo mogą inwazyjne kontenery, takie jak wspierane przez boost , a Qt często używał ich we wcześniejszych wersjach, ale nie są one używane jako znacznie więcej, ponieważ są one trudne w użyciu, niebezpieczne i nakładają ciężar na programistę. Krowa jest znacznie mniej inwazyjnym rozwiązaniem, ale nieatrakcyjnym z powodów przedstawionych powyżej.

Nie ma powodu, dla którego nie można by używać kontenerów STL o takim samym koszcie pamięci lub niższym niż kontenery Qt, z dodatkową korzyścią polegającą na faktycznej wiedzy, ile pamięci będzie się marnować w danym momencie. Niestety nie da się ich porównać w surowym zużyciu pamięci, ponieważ takie benchmarki pokazywałyby szalenie różne wyniki w różnych przypadkach użycia, który jest dokładnie rodzaj problemu, że STL został zaprojektowany, aby rozwiązać.

In Conclusion

Unikaj używania kontenerów Qt, gdy jest to możliwe, aby to zrobić bez nakładania kosztów kopiowania, i używaj iteracji typu STL (być może poprzez wrapper lub nową składnię), gdy tylko jest to możliwe.

 24
Author: Alice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-01 23:58:02

Kontenery STL:

  • mieć gwarancje wydajności
  • może być stosowany w algorytmach STL , które również mają gwarancje wydajności
  • Może być wykorzystany przez inne biblioteki C++, takie jak Boost Są standardowe i prawdopodobnie przetrwają autorskie rozwiązania]}
  • zachęcanie do ogólnego programowania algorytmów i struktur danych. Jeśli napiszesz nowe algorytmy i struktury danych zgodne z STL, możesz wykorzystać to, co już zapewnia STL na nie koszt.
 21
Author: fbrereto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-03 21:20:16

Kontenery Qt używają idiomu copy-on-write.

 15
Author: TimW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-03 16:03:25

Jednym z głównych problemów jest to, że API Qt oczekuje od ciebie dostarczenia danych w kontenerach Qt, więc równie dobrze możesz po prostu użyć kontenerów Qt zamiast przekształcać je tam i z powrotem.

Ponadto, jeśli już używasz kontenerów Qt, może być nieco bardziej optymalne użycie ich wyłącznie, ponieważ nie musiałbyś dołączać plików nagłówkowych STL i potencjalnie linkować do bibliotek STL. Jednak w zależności od zestawu narzędzi może się to zdarzyć. Wyłącznie z perspektywa projektowa, spójność jest ogólnie dobrą rzeczą.

 9
Author: qid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-03 17:03:35

Jeśli dane, z którymi pracujesz, są używane głównie do obsługi interfejsu opartego na Qt, zdecydowanie użyj kontenerów Qt.

Jeśli dane są używane głównie wewnętrznie w aplikacji i nigdy nie będziesz musiał przenosić się z Qt, a następnie z wyjątkiem problemów z wydajnością, użyj kontenerów Qt, ponieważ ułatwi to obsługę bitów danych, które trafiają do interfejsu użytkownika.

Jeśli dane są używane głównie w połączeniu z innymi bibliotekami, które wiedzą tylko o kontenerach STL, użyj kontenerów STL. Jeśli w takiej sytuacji masz kłopoty bez względu na wszystko, ponieważ będziesz robił wiele portowań między typami kontenerów bez względu na to, co robisz.

 8
Author: Michael Kohne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-03 21:29:09

Poza różnicą krów, kontenery STL są znacznie szerzej obsługiwane na różnych platformach. Qt jest wystarczająco przenośny, jeśli ograniczysz swoją pracę do platform "mainstreamowych" , ale STL jest dostępny również na wielu innych, bardziej niejasnych platformach (np. DSP Texas Instruments).

Ponieważ STL jest standardem, a nie kontrolowanym przez jedną korporację, jest, ogólnie rzecz biorąc, więcej programistów, którzy mogą łatwo czytać, rozumieć i modyfikować kod STL oraz więcej zasobów (książek, fora internetowe, konferencje itp.), aby wesprzeć ich w tym, niż jest to dla Qt. Nie oznacza to, że należy unikać Qt tylko z tego powodu; po prostu, że wszystkie inne rzeczy są równe, powinieneś domyślać się STL, ale oczywiście wszystkie rzeczy są rzadko równe, więc będziesz musiał zdecydować we własnym kontekście, który ma największy sens.

W odniesieniu do odpowiedzi Alexkra: wydajność STL jest gwarantowana w granicach, ale dana implementacja może korzystać z szczegóły zależne od platformy, aby przyspieszyć ich STL. Więc w tym sensie, można uzyskać różne wyniki na różnych platformach, ale nigdy nie będzie wolniej niż explicit guarantee (modulo bugs).

 7
Author: metal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-03 16:29:43

Moje pięć centów: Kontenery Qt powinny działać podobnie na różnych platformach. Natomiast kontenery STL zależą od implementacji STL. Możesz uzyskać różne wyniki wydajności.

EDIT: Nie mówię, że STL jest "wolniejszy", ale wskazuję na efekty różne szczegóły realizacji.
Proszę sprawdzić to , a potem może to.
I to nie jest prawdziwy problem STL. Oczywiście, jeśli masz znaczną różnicę w wydajności, to jest problem w kodzie używającym STL.

 3
Author: alexkr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:18

To chyba zależy od tego jak używasz Qt. Jeśli używasz go na całym produkcie, prawdopodobnie ma sens używanie kontenerów Qt. Jeśli zawiera się go tylko (na przykład) w części interfejsu użytkownika, może być lepiej użyć standardowych kontenerów C++.

 3
Author: Nemanja Trifunovic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-03 21:14:46

Jestem zdania, że STL jest doskonałym oprogramowaniem, jednak jeśli mam wykonać jakieś programowanie związane z KDE lub Qt, to Qt jest dobrym rozwiązaniem. Również to zależy od kompilatora, którego używasz, z GCC STL działa całkiem dobrze, jednak jeśli musisz użyć say Sun Studio CC, STL najprawdopodobniej przyniesie Ci bóle głowy z powodu kompilatora, a nie STL per se. W takim przypadku, ponieważ kompilator sprawi, że głowa będzie bolała, użyj Qt, aby zaoszczędzić Ci kłopotów. Tylko moje 2 centy...

 3
Author: Paulo Lopes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-03 21:25:00

W Qvectorze istnieje (czasami) duże ograniczenie. może przydzielić tylko int bajtów pamięci (Należy pamiętać, że limit jest w bajtach, a nie w liczbie elementów). Oznacza to, że próba przydzielenia sąsiednich bloków pamięci większych niż ~2GB za pomocą Qvectora doprowadzi do awarii. Dzieje się tak w przypadku Qt 4 i 5. std:: vector nie ma takiego ograniczenia.

 3
Author: fedemp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-25 13:35:24

Głównym powodem, dla którego korzystam z kontenerów STL, jest potrzeba niestandardowego alokatora, aby ponownie wykorzystać pamięć w bardzo dużych kontenerach. Załóżmy na przykład, że masz Qmapę, która przechowuje 1000000 wpisów (pary klucz/wartość). W Qt oznacza to dokładnie 1000000 milionów wywołań (new) bez względu na wszystko. W STL zawsze możesz utworzyć własny alokator, który wewnętrznie przydziela całą tę pamięć naraz i przydziela ją do każdego wpisu w miarę wypełniania mapy.

Radzę używać STL kontenery podczas pisania algorytmów o znaczeniu krytycznym dla wydajności w logice biznesowej, a następnie konwertowania ich z powrotem do kontenerów Qt, gdy wyniki są gotowe do wyświetlania przez kontrolki i formularze interfejsu użytkownika w razie potrzeby.

 0
Author: Darien Pardinas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-20 22:32:08