Bu iddiaları gerçek ölçülebilir olaylara ayıralım:
- Daha hafif: Qt kapları STL kaplarından daha az bellek kullanır
- Daha güvenli: Qt konteynerlerin yanlış kullanılması için daha az fırsatı vardır
- Daha kolay: Qt konteynırları daha az entelektüel bir yük sunar
Daha kolay
Bu bağlamda öne sürülen iddia, java tarzı yinelemenin STL stilinden bir şekilde "daha kolay" olması ve bu nedenle bu ek arayüz nedeniyle Qt'nin daha kolay kullanılmasıdır.
Java Stili:
QListIterator<QString> i(list);
while (i.hasNext())
qDebug() << i.next();
STL Tarzı:
QList<QString>::iterator i;
for (i = list.begin(); i != list.end(); ++i)
qDebug << *i;
Java yineleyici stili biraz daha küçük ve daha temiz olma avantajına sahiptir. Sorun şu ki, bu aslında STL tarzı değil.
C ++ 11 STL Stili
for( auto i = list.begin(); i != list.end(); ++i)
qDebug << *i;
veya
C ++ 11 foreach tarzı
for (QString i : list)
qDebug << i;
Bu o kadar basittir ki, başka bir şey kullanmanız için hiçbir neden yoktur (C ++ 11'i desteklemediğiniz sürece).
Benim favorim ise:
BOOST_FOREACH(QString i, list)
{
qDebug << i;
}
Gördüğümüz gibi, bu arayüz bize zaten şık, aerodinamik ve modern bir arayüzün üstünde ek bir arayüz dışında hiçbir şey kazanmıyor. Zaten kararlı ve kullanılabilir bir arabirimin üzerine gereksiz düzeyde bir soyutlama mı ekliyorsunuz? Benim "kolay" fikrim değil.
Ayrıca, Qt foreach ve java arayüzleri ek yük ekler; yapıyı kopyalar ve gereksiz düzeyde bir dolaylama sağlar. Bu çok fazla görünmeyebilir, ancak neden bu kadar basit olmayan bir arayüz sağlamak için bir ek yük katmanı eklemelisiniz? Java bu arabirime sahiptir çünkü java'da aşırı yükleme yoktur; C ++ yapar.
Daha güvenli
Qt'nin verdiği gerekçe, ne örtük ne de bir sorun olan örtük paylaşım problemidir. Ancak paylaşmayı da içerir.
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.
*/
İlk olarak, bu örtük değildir; açıkça bir vektörü diğerine atarsınız. STL yineleyici belirtimi, yineleyicilerin kaba ait olduğunu açıkça gösterir, bu nedenle b ve a arasında paylaşılan bir konteyner tanıttık. İkincisi, bu bir sorun değil; yineleyici belirtiminin tüm kurallarına uyulduğu sürece, kesinlikle hiçbir şey yanlış gitmez. Bir şeylerin yanlış gittiği tek zaman burada:
b.clear(); // Now the iterator i is completely invalid.
Qt bunu sanki bir şey ifade ediyormuş gibi belirtir, çünkü bu senaryodan bir sorun çıkmış gibi. Öyle değil. Yineleyici geçersiz kılınmıştır ve tıpkı birden fazla ayrık alandan erişilebilen her şey gibi, bu da tam olarak böyle çalışır. Aslında, Qt'daki Java stili yineleyicilerle kolayca ortaya çıkacaktır, çünkü burada ve diğer birçok alanda belgelendiği gibi bir antipattern olan örtük paylaşıma büyük ölçüde güvenmektedir . Bu "optimizasyonun" çok iş parçacılığa doğru giderek daha fazla hareket eden bir çerçevede kullanılması özellikle garip görünüyor, ama bu sizin için pazarlama.
çakmak
Bu biraz daha hileli. Yazarken Kopyala ve Örtülü Paylaşım ve Büyüme Stratejilerinin kullanılması, kabınızın herhangi bir zamanda ne kadar bellek kullanacağı konusunda garanti vermeyi çok zorlaştırır. Bu, size güçlü algoritmik garantiler veren STL'den farklıdır.
Bir vektör için boşa giden alanın minimal sınırının, vektörün uzunluğunun kare kökü olduğunu biliyoruz , ancak bunu Qt'de uygulamanın hiçbir yolu yok gibi görünüyor; destekledikleri çeşitli "optimizasyonlar" bu çok önemli yer tasarrufu özelliğini engelleyecektir. STL bu özelliği gerektirmez (ve çoğu daha israflı olan iki kat büyüme sağlar), ancak gerekirse en azından bu özelliği uygulayabileceğinizi not etmek önemlidir.
Aynı durum, kullanılan alanı önemli ölçüde azaltmak için XOr linkini kullanabilen çift bağlantılı listeler için de geçerlidir. Yine, büyüme ve COW gereksinimleri nedeniyle Qt ile bu mümkün değildir.
COW gerçekten daha hafif bir şey yapabilir, ancak boost tarafından desteklenen Intrusive Container'lar da kullanılabilir ve Qt bunları önceki sürümlerde sık sık kullandı, ancak artık kullanılmadıkları, güvensiz oldukları ve bir yük yükledikleri için artık kullanılmıyorlar programcı üzerinde. COW çok daha az müdahaleci bir çözümdür, ancak yukarıda belirtilen nedenlerden dolayı çekici değildir.
Herhangi bir zamanda ne kadar bellek harcayacağınızı bilmenin ek avantajı ile Qt konteynırlarından aynı veya daha düşük maliyetli STL kaplarını kullanamamanızın bir nedeni yoktur. Ne yazık ki, ham bellek kullanımında ikisini karşılaştırmak imkansızdır, çünkü bu tür karşılaştırmalar farklı kullanım durumlarında çılgınca farklı sonuçlar gösterecektir, bu da STL'nin düzeltmek için tasarlandığı tam bir problemdir.
Sonuç olarak
Kopyalama maliyeti koymadan mümkün olduğunda Qt Kapları kullanmaktan kaçının ve mümkünse STL tipi yinelemeyi (belki bir sarıcı veya yeni sözdizimi yoluyla) kullanın.