Saya mulai dengan menggunakan std::(w)string
dan wadah STL secara eksklusif dan mengkonversi ke / dari setara Qt, tapi saya sudah beralih ke QString
dan saya menemukan bahwa saya menggunakan wadah Qt semakin banyak.
Ketika datang ke string, QString
menawarkan fungsionalitas yang jauh lebih lengkap dibandingkan dengan std::basic_string
dan itu sepenuhnya sadar Unicode. Ini juga menawarkan implementasi SAP yang efisien , yang sangat saya andalkan.
Kontainer Qt:
- menawarkan implementasi SAP yang sama seperti pada
QString
, yang sangat berguna ketika menggunakan foreach
makro Qt (yang menyalin) dan ketika menggunakan meta-type atau sinyal dan slot.
- dapat menggunakan iterator gaya-STL atau iterator gaya-Java
- dapat di-stream dengan
QDataStream
- digunakan secara luas di Qt's API
- memiliki implementasi yang stabil di seluruh sistem operasi. Implementasi STL harus mematuhi standar C ++, tetapi sebaliknya bebas untuk melakukan apa yang diinginkan (lihat
std::string
kontroversi Kontrak Karya). Beberapa implementasi STL sangat buruk.
- berikan hash, yang tidak tersedia kecuali Anda menggunakan TR1
QTL memiliki filosofi yang berbeda dari STL, yang dirangkum dengan baik oleh J. Blanchette: "Sementara kontainer STL dioptimalkan untuk kecepatan mentah, kelas-kelas kontainer Qt telah dirancang dengan cermat untuk memberikan kenyamanan, penggunaan memori minimal, dan perluasan kode minimal."
Tautan di atas memberikan detail lebih lanjut tentang penerapan QTL dan optimasi apa yang digunakan.
QList<double>
pada arsitektur 32-bit untuk penggunaan memori untuk melihat sendiri.QVector
alih-alihQList
. Ada cukup penjelasan Qt, bahwa QList dirancang untuk menyimpan pointer pada objek. Jadi setiap item ganda yang dibuat secara dinamis dan pointer ke item ini disimpanQList
. QList dirancang sebagai wadah "tengah" antara vektor dan daftar tertaut. Ini tidak dirancang untuk kasus kritis memori / kinerja.Ini adalah pertanyaan yang sulit dijawab. Ini benar-benar dapat mengarah pada argumen filosofis / subyektif.
Yang telah dibilang...
Saya merekomendasikan aturan "Ketika di Roma ... Lakukan seperti yang dilakukan orang Roma"
Yang berarti jika Anda berada di tanah Qt, kode seperti yang dilakukan orang Qtia. Ini bukan hanya untuk masalah keterbacaan / konsistensi. Pertimbangkan apa yang terjadi jika Anda menyimpan semuanya dalam wadah stl maka Anda harus meneruskan semua data itu ke fungsi Qt. Apakah Anda benar-benar ingin mengelola banyak kode yang menyalin hal-hal ke / keluar dari wadah Qt. Kode Anda sudah sangat bergantung pada Qt, jadi tidak seperti Anda membuatnya lebih "standar" dengan menggunakan wadah stl. Dan apa gunanya sebuah wadah jika setiap kali Anda ingin menggunakannya untuk sesuatu yang bermanfaat, Anda harus menyalinnya ke dalam wadah Qt yang sesuai?
sumber
Wadah Qt lebih terbatas daripada yang STL. Beberapa contoh di mana yang STL lebih unggul (semua ini saya tekan di masa lalu):
QList
(berbasis pointer) danQValueList
(berbasis nilai); Qt 3 punyaQPtrList
danQValueList
; Qt 4 sekarang punyaQList
, dan tidak ada yang sukaQPtrList
atau tidak sama sekaliQValueList
).Bahkan jika Anda akhirnya menggunakan wadah Qt, gunakan subset API yang kompatibel dengan STL (mis.
push_back()
, Bukanappend()
;,front()
bukanfirst()
, ...) untuk menghindari porting lagi pada Qt 5. Di Qt2-> 3 dan Qt3-> 4 transisi, perubahan dalam kontainer Qt adalah di antara mereka yang membutuhkan kode churn paling banyak.rbegin()
/rend()
, membuat iterasi terbalik simetris untuk meneruskan iterasi. Tidak semua kontainer Qt memilikinya (yang asosiatif tidak), jadi membalikkan iterasi tidak perlu rumit.insert()
dari jenis iterator yang berbeda, tetapi kompatibel, sehinggastd::copy()
jauh lebih jarang dibutuhkan.Allocator
argumen templat, membuat sepele manajemen memori kustom (diperlukan typedef), dibandingkan dengan Qt (garpuQLineEdit
diperlukan untuks/QString/secqstring/
). EDIT 20171220 : Ini memotong Qt off dari kemajuan dalam desain pengalokasi setelah C ++ 11 dan C ++ 17, lih. mis . pembicaraan John Lakos ( bagian 2 ).std::deque
.std::list
telahsplice()
. Setiap kali saya menemukan diri saya menggunakanstd::list
, itu karena saya perlusplice()
.std::stack
,std::queue
Benar agregat kontainer yang mendasarinya, dan tidak mewarisi itu, sebagaiQStack
,QQueue
lakukan.QSet
sepertistd::unordered_set
, tidak sukastd::set
.QList
adalah hanya aneh .Banyak hal di atas dapat diselesaikan dengan mudah di Qt , tetapi perpustakaan kontainer di Qt tampaknya mengalami kurangnya fokus pengembangan saat ini.
EDIT 20150106 : Setelah menghabiskan beberapa waktu mencoba membawa dukungan C ++ 11 ke kelas kontainer Qt 5, saya telah memutuskan bahwa itu tidak layak untuk dikerjakan. Jika Anda melihat pekerjaan yang dimasukkan ke dalam implementasi pustaka standar C ++, cukup jelas bahwa kelas Qt tidak akan pernah menyusul. Kami telah merilis Qt 5.4 sekarang dan
QVector
masih tidak memindahkan elemen pada realokasi, tidak memilikiemplace_back()
atau menilai ulangpush_back()
... Kami juga baru saja menolakQOptional
templat kelas, sebagaistd::optional
gantinyamenunggu. Demikian juga untukstd::unique_ptr
. Saya berharap tren itu berlanjut.sumber
QList
itu setara denganstd::deque
. Jelas, saya seharusnya tidak membaca sekilas dokumentasi.QVector
telah memilikicrbegin
dan teman-teman sejak Qt 5.6std::reverse_iterator
lebih dari yang rusakQHash
/QMap
iterator, yang, ketika dereferenced, kembalimapped_type
bukanvalue_type
). Tidak ada yang tidak bisa diperbaiki, tetapi lihat EDIT saya mulai tahun 2015.QVector
menggunakanint
sebagai indeksnya, sehingga membatasi ukuran 31-bit (bahkan pada sistem 64-bit). Selain itu, ia bahkan tidak dapat menyimpanINT_MAX
elemen berukuran lebih besar dari 1 byte. Misalnya, yang terbesar yang.size()
dapat saya milikiQVector<float>
di x86_64 Linux gcc adalah 536870907 elemen (2²⁹-5), sementarastd::vector<float>
berhasil mengalokasikan 4294967295 elemen (2³²-1; tidak mencoba lagi karena kurangnya RAM untuk ini (ukuran ini sudah memakan waktu 16 GiB) ).Mari pilah klaim-klaim ini menjadi fenomena terukur yang sebenarnya:
Lebih mudah
Klaim yang dibuat dalam konteks ini adalah bahwa iterasi gaya java entah bagaimana "lebih mudah" daripada gaya STL, dan karenanya Qt lebih mudah digunakan karena antarmuka tambahan ini.
Gaya Jawa:
Gaya STL:
Gaya iterator Java memiliki keuntungan menjadi sedikit lebih kecil dan lebih bersih. Masalahnya adalah, ini bukan gaya STL lagi.
C ++ 11 STL Style
atau
C ++ 11 gaya foreach
Yang sangat sederhana sehingga tidak ada alasan untuk menggunakan hal lain (kecuali Anda tidak mendukung C ++ 11).
Namun, favorit saya adalah:
Jadi, seperti yang bisa kita lihat, antarmuka ini tidak memberi kita apa-apa selain antarmuka tambahan, selain antarmuka yang sudah ramping, ramping, dan modern. Menambahkan level abstraksi yang tidak perlu di atas antarmuka yang sudah stabil dan dapat digunakan? Bukan ide saya "lebih mudah".
Juga, antarmuka Qt foreach dan java menambahkan overhead; mereka menyalin struktur, dan memberikan tingkat tipuan yang tidak perlu. Ini mungkin tidak terlalu banyak, tetapi mengapa menambahkan lapisan overhead untuk menyediakan antarmuka yang tidak terlalu sederhana? Java memiliki antarmuka ini karena java tidak memiliki operator kelebihan; C ++ tidak.
Lebih aman
Pembenaran yang diberikan Qt adalah masalah berbagi implisit, yang tidak implisit maupun masalah. Namun itu melibatkan berbagi.
Pertama, ini bukan implisit; Anda secara eksplisit menetapkan satu vektor ke yang lain. Spesifikasi iterator STL dengan jelas menunjukkan bahwa iterator termasuk dalam wadah, jadi kami telah dengan jelas memperkenalkan wadah bersama antara b dan a. Kedua, ini bukan masalah; selama semua aturan spesifikasi iterator dipatuhi, sama sekali tidak ada yang salah. Satu-satunya saat ada yang salah ada di sini:
Qt menetapkan ini seolah-olah itu berarti sesuatu, seperti masalah muncul de novo dari skenario ini. Tidak. Iterator tidak valid, dan sama seperti apa pun yang dapat diakses dari beberapa area terpisah, ini hanya cara kerjanya. Bahkan, ini akan terjadi dengan mudah dengan iterator gaya Java di Qt, berkat sangat bergantung pada berbagi implisit, yang merupakan antipemutakhir seperti yang didokumentasikan di sini , dan di banyak daerah lainnya . Tampaknya aneh untuk "optimasi" ini mulai digunakan dalam kerangka kerja yang bergerak semakin banyak menuju multithreading, tapi itu pemasaran untuk Anda.
Lebih ringan
Yang ini agak rumit. Penggunaan Copy-On-Write dan Berbagi Secara implisit dan Strategi Pertumbuhan membuatnya sangat sulit untuk benar-benar membuat jaminan tentang berapa banyak memori yang akan digunakan wadah Anda pada waktu tertentu. Ini tidak seperti STL, yang memberi Anda jaminan algoritmik yang kuat.
Kita tahu batas minimal ruang terbuang untuk vektor adalah akar kuadrat dari panjang vektor , tetapi tampaknya tidak ada cara untuk mengimplementasikannya dalam Qt; berbagai "optimisasi" yang didukungnya akan menghalangi fitur penghematan ruang yang sangat penting ini. STL tidak memerlukan fitur ini (dan sebagian besar menggunakan pertumbuhan dua kali lipat, yang lebih boros), tetapi penting untuk dicatat bahwa Anda setidaknya bisa mengimplementasikan fitur ini, jika perlu.
Hal yang sama berlaku untuk daftar tertaut ganda, yang dapat menggunakan tautan XOr untuk secara drastis mengurangi ruang yang digunakan. Sekali lagi, ini tidak mungkin dengan Qt, karena persyaratan untuk pertumbuhan dan SAP.
SAP memang dapat membuat sesuatu lebih ringan, tetapi Wadah Intrusif, seperti didukung oleh boost , dan Qt sering digunakan dalam versi sebelumnya, tetapi mereka tidak digunakan lagi karena mereka sulit digunakan, tidak aman, dan membebani beban. pada programmer. SAP adalah solusi yang jauh lebih tidak mengganggu, tetapi tidak menarik karena alasan yang disebutkan di atas.
Tidak ada alasan mengapa Anda tidak bisa menggunakan wadah STL dengan biaya memori yang sama atau kurang dari wadah Qt, dengan manfaat tambahan sebenarnya mengetahui berapa banyak memori yang akan Anda buang pada waktu tertentu. Sayangnya, mustahil untuk membandingkan keduanya dalam penggunaan memori mentah, karena tolok ukur seperti itu akan menunjukkan hasil yang sangat berbeda dalam kasus penggunaan yang berbeda, yang merupakan jenis masalah yang STL dirancang untuk diperbaiki.
Kesimpulannya
Hindari penggunaan Qt Containers bila memungkinkan untuk melakukannya tanpa membebankan biaya penyalinan, dan gunakan iterasi tipe STL (mungkin melalui pembungkus atau sintaks baru), bila memungkinkan.
sumber
Adding an unnecessary level of abstraction on top of an already stable and usable interface? Not my idea of "easier".
iterator gaya Java Qt tidak ditambahkan ke C ++ 11; mereka mendahului itu. Pokoknya Qt'sforeach(QString elem, list)
semudah foreach C ++ 11 atau BOOST_FOREACH dan bekerja dengan kompiler yang sesuai dengan pra-C ++ 11.So, as we can see, this interface gains us nothing except an additional interface, *on top of* an already sleek, streamlined, and modern interface. Adding an unnecessary level of abstraction on top of an already stable and usable interface? Not my idea of "easier".
(penekanan saya) Anda mengatakan ini tepat setelah Anda menunjukkan kepada kami versi C ++ 11 dan BOOST foreach, membuatnya terdengar seperti versi Qt dibangun dari salah satu dari keduanya, yang bukan merupakan kasus AFAICT. Saya yakin itu bukan apa yang Anda maksudkan, tetapi justru itulah yang menjadi penyebabnya. Karenanya "informasi menyesatkan".It's an additional layer of abstraction (and an unnecessary one) that bloats the interface, which is not easier.
Masih belum jelas apa yang Anda bandingkan. C ++ 03 iterators? C ++ 11 iterator? BOOST_FOREACH? Semua yang di atas?Wadah STL:
sumber
Wadah Qt menggunakan idiom copy-on-write.
sumber
std::basic_string
dan standar mengambil tindakan dengan C ++ 11 untuk membuat ini tidak sesuai.Salah satu masalah utama adalah bahwa Qt's API mengharapkan Anda untuk memberikan data dalam wadah Qt, jadi Anda mungkin juga cukup menggunakan wadah Qt daripada mengubah bolak-balik antara keduanya.
Juga, jika Anda sudah menggunakan kontainer Qt, mungkin akan sedikit lebih optimal untuk menggunakannya secara eksklusif, karena Anda tidak harus menyertakan file header STL dan berpotensi menautkan di perpustakaan STL. Namun, tergantung pada rantai alat Anda, itu mungkin terjadi. Murni dari perspektif desain, konsistensi pada umumnya adalah hal yang baik.
sumber
Jika data yang Anda gunakan sebagian besar digunakan untuk menggerakkan UI berbasis Qt, maka pasti gunakan kontainer Qt.
Jika sebagian besar data digunakan secara internal di aplikasi, dan Anda tidak akan pernah berpeluang jauh dari Qt, maka jika tidak ada masalah kinerja, gunakan wadah Qt karena itu akan membuat bit data yang masuk ke UI lebih mudah untuk ditangani.
Jika sebagian besar data digunakan bersama dengan perpustakaan lain yang hanya tahu tentang wadah STL, maka gunakan wadah STL. Jika Anda memiliki situasi ini, Anda dalam masalah apa pun karena Anda akan melakukan banyak bolak-balik di antara jenis wadah apa pun yang Anda lakukan.
sumber
Selain perbedaan SAP, wadah STL jauh lebih banyak didukung pada berbagai platform. Qt cukup portabel jika Anda membatasi pekerjaan Anda pada platform "arus utama", tetapi STL juga tersedia di banyak platform lain yang tidak jelas (mis., DSP Texas Instruments).
Karena STL adalah standar daripada dikendalikan oleh satu perusahaan, ada, secara umum, lebih banyak programmer yang dapat dengan mudah membaca, memahami, dan memodifikasi kode STL dan lebih banyak sumber daya (buku, forum online, konferensi, dll.) Untuk mendukung mereka dalam melakukan ini daripada Qt. Itu bukan untuk mengatakan bahwa seseorang harus menghindar dari Qt karena alasan ini saja; Hanya saja, semua hal lain dianggap sama, Anda harus default ke STL, tetapi tentu saja semua hal jarang sama, jadi Anda harus memutuskan dalam konteks Anda sendiri yang paling masuk akal.
Sehubungan dengan jawaban AlexKR: kinerja STL dijamin dalam batas, tetapi implementasi yang diberikan dapat menggunakan detail yang bergantung pada platform untuk mempercepat STL mereka. Jadi dalam hal itu, Anda mungkin mendapatkan hasil yang berbeda pada platform yang berbeda, tetapi itu tidak akan pernah lebih lambat daripada jaminan eksplisit (bug modulo).
sumber
Lima sen saya: Wadah Qt seharusnya berfungsi serupa pada platform berbeda. Sementara wadah STL tergantung pada implementasi STL. Anda mungkin mendapatkan hasil kinerja yang berbeda.
EDIT: Saya tidak mengatakan bahwa STL "lebih lambat" tetapi saya menunjukkan efek dari berbagai detail implementasi.
Silakan periksa ini , dan mungkin ini .
Dan itu bukan masalah nyata STL. Jelas, jika Anda memiliki perbedaan kinerja yang signifikan, maka ada masalah dalam kode yang menggunakan STL.
sumber
Saya kira itu tergantung pada cara Anda menggunakan Qt. Jika Anda menggunakannya di seluruh produk Anda, maka mungkin masuk akal untuk menggunakan wadah Qt. Jika Anda hanya berisi untuk (misalnya) bagian UI, mungkin lebih baik menggunakan wadah standar C ++.
sumber
Saya berpendapat bahwa STL adalah perangkat lunak yang sangat baik namun jika saya melakukan beberapa pemrograman terkait KDE atau Qt maka Qt adalah cara yang harus dilakukan. Juga tergantung pada kompiler yang Anda gunakan, dengan GCC STL bekerja cukup baik namun jika Anda harus menggunakan katakanlah SUN Studio CC maka STL kemungkinan besar akan membawa Anda sakit kepala karena kompiler bukan STL per se. Dalam hal ini karena kompiler akan membuat kepala Anda sakit, cukup gunakan Qt untuk menyelamatkan Anda dari masalah. Hanya 2 sen saya ...
sumber
Ada (kadang-kadang) batasan besar dalam QVector. Itu hanya dapat mengalokasikan memori byte int (perhatikan bahwa batasnya adalah dalam byte bukan dalam jumlah elemen). Ini menyiratkan bahwa mencoba mengalokasikan blok memori berdekatan yang lebih besar dari ~ 2GB dengan QVector akan menyebabkan crash. Ini terjadi dengan Qt 4 dan 5. std :: vector tidak memiliki batasan seperti itu.
sumber
Alasan utama untuk menggunakan wadah STL untuk saya adalah jika Anda memerlukan pengalokasi khusus untuk menggunakan kembali memori dalam wadah yang sangat besar. Misalkan misalnya Anda memiliki QMap yang menyimpan 1000000 entri (pasangan kunci / nilai). Dalam Qt yang menyiratkan alokasi persis 10.000.000 juta (
new
panggilan) apa pun yang terjadi. Di STL Anda selalu dapat membuat pengalokasi khusus yang secara internal mengalokasikan semua memori itu sekaligus dan menetapkannya untuk setiap entri saat peta diisi.Saran saya adalah menggunakan wadah STL saat menulis algoritma kinerja kritis dalam logika bisnis dan kemudian mengubahnya kembali ke wadah Qt ketika hasilnya siap dengan ditampilkan oleh kontrol dan formulir UI Anda jika diperlukan.
sumber
QMapNode<K,V>
untuk AndaK
,V
untuk menyediakannya sendirioperator new
.