ลองแยกข้อเรียกร้องเหล่านี้ออกเป็นปรากฏการณ์ที่วัดได้จริง:
- ไฟแช็ก: คอนเทนเนอร์ Qt ใช้หน่วยความจำน้อยกว่าคอนเทนเนอร์ STL
- ปลอดภัยยิ่งขึ้น: ตู้คอนเทนเนอร์ Qt มีโอกาสน้อยที่จะใช้อย่างไม่เหมาะสม
- ง่ายกว่า: คอนเทนเนอร์ Qt มีภาระทางปัญญาน้อยลง
ง่ายดาย
การอ้างสิทธิ์ที่เกิดขึ้นในบริบทนี้คือการทำซ้ำสไตล์ Java เป็นอย่างใด "ง่าย" กว่าสไตล์ STL และดังนั้น Qt ใช้งานได้ง่ายขึ้นเนื่องจากส่วนต่อประสานเพิ่มเติมนี้
สไตล์ชวา:
QListIterator<QString> i(list);
while (i.hasNext())
qDebug() << i.next();
สไตล์ STL:
QList<QString>::iterator i;
for (i = list.begin(); i != list.end(); ++i)
qDebug << *i;
สไตล์ Java iterator มีประโยชน์ในการมีขนาดเล็กลงและสะอาดขึ้นเล็กน้อย ปัญหาคือนี่ไม่ใช่สไตล์ STL จริง ๆ อีกต่อไป
สไตล์ C ++ 11 STL
for( auto i = list.begin(); i != list.end(); ++i)
qDebug << *i;
หรือ
C ++ 11 foreach style
for (QString i : list)
qDebug << i;
ซึ่งง่ายอย่างมากที่ไม่มีเหตุผลอะไรเลยที่จะใช้สิ่งอื่น (เว้นแต่คุณจะไม่รองรับ C ++ 11)
อย่างไรก็ตามสิ่งที่ฉันชอบคือ:
BOOST_FOREACH(QString i, list)
{
qDebug << i;
}
ดังที่เราเห็นอินเทอร์เฟซนี้ทำให้เราไม่มีอะไรนอกจากอินเทอร์เฟซเพิ่มเติมนอกเหนือจากอินเทอร์เฟซที่ทันสมัยคล่องตัวและทันสมัย การเพิ่มระดับนามธรรมที่ไม่จำเป็นบนอินเทอร์เฟซที่เสถียรและใช้งานแล้ว? ไม่ใช่ความคิดของฉันที่ "ง่ายขึ้น"
นอกจากนี้อินเตอร์เฟส Qt foreach และ java เพิ่มโอเวอร์เฮด; พวกเขาคัดลอกโครงสร้างและให้ระดับความไม่จำเป็นของการอ้อม นี่อาจดูเหมือนไม่มาก แต่ทำไมเพิ่มเลเยอร์ของค่าใช้จ่ายเพื่อให้อินเทอร์เฟซที่ไม่มากง่ายกว่า? Java มีส่วนต่อประสานนี้เนื่องจาก java ไม่มีตัวดำเนินการมากเกินไป C ++ ทำ
ปลอดภัยมากขึ้น
เหตุผลที่ Qt ให้นั้นคือปัญหาการแบ่งปันโดยปริยายซึ่งไม่ใช่ทั้งปัญหาและโดยปริยาย อย่างไรก็ตามเกี่ยวข้องกับการแบ่งปัน
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.
*/
ครั้งแรกนี้ไม่ได้โดยปริยาย คุณกำลังกำหนดเวกเตอร์หนึ่งรายการให้กับอีกเวกเตอร์หนึ่งอย่างชัดเจน ข้อมูลจำเพาะตัววนซ้ำ STL ระบุอย่างชัดเจนว่าตัววนซ้ำอยู่ในคอนเทนเนอร์ดังนั้นเราจึงแนะนำคอนเทนเนอร์ที่ใช้ร่วมกันอย่างชัดเจนระหว่าง b และ a ประการที่สองนี่ไม่ใช่ปัญหา ตราบใดที่มีการปฏิบัติตามกฎทั้งหมดของข้อกำหนดตัววนซ้ำไม่มีอะไรผิดปกติ มีเพียงบางสิ่งที่ผิดพลาดอยู่ที่นี่:
b.clear(); // Now the iterator i is completely invalid.
Qt ระบุสิ่งนี้ราวกับว่ามันหมายถึงบางสิ่งบางอย่างเช่นปัญหาที่เกิดขึ้น de novo จากสถานการณ์นี้ มันไม่ได้ ตัววนซ้ำไม่ถูกต้องและเหมือนกับทุกสิ่งที่สามารถเข้าถึงได้จากหลายพื้นที่ที่แยกจากกันนี่เป็นวิธีการทำงาน ในความเป็นจริงนี้จะเกิดขึ้นพร้อมกับ Java iterators สไตล์น่ารักขอบคุณที่มันเป็นอย่างมากการพึ่งพาการใช้ร่วมกันโดยปริยายซึ่งเป็น antipattern เป็นเอกสารที่นี่และที่อื่น ๆ อีกหลายพื้นที่พื้นที่ดูเหมือนจะแปลกเป็นพิเศษสำหรับ "การเพิ่มประสิทธิภาพ" นี้ที่จะนำไปใช้ในกรอบการทำงานที่เพิ่มมากขึ้นไปสู่การทำมัลติเธรด แต่นั่นเป็นการตลาดสำหรับคุณ
ไฟแช็ก
อันนี้ค่อนข้างหลอกลวง การใช้กลยุทธ์การคัดลอก - เขียน - และการแบ่งปันและการเติบโตโดยปริยายทำให้ยากมากที่จะรับประกันว่าหน่วยความจำของคุณจะใช้คอนเทนเนอร์เท่าไรในเวลาใดก็ตาม ซึ่งแตกต่างจาก STL ซึ่งให้การรับประกันอัลกอริทึมที่แข็งแกร่งแก่คุณ
เรารู้ขอบเขตที่น้อยที่สุดของการสูญเสียพื้นที่สำหรับเวกเตอร์คือสแควร์รูทของความยาวของเวกเตอร์แต่ดูเหมือนว่าจะไม่มีวิธีการใช้สิ่งนี้ใน Qt; "การปรับให้เหมาะสม" แบบต่าง ๆ ที่พวกเขาสนับสนุนจะกีดกันคุณลักษณะการประหยัดพื้นที่ที่สำคัญมากนี้ STL ไม่ต้องการคุณลักษณะนี้ (และส่วนใหญ่ใช้การเติบโตเพิ่มขึ้นสองเท่าซึ่งสิ้นเปลืองมากกว่า) แต่สิ่งสำคัญคือต้องทราบว่าอย่างน้อยคุณสามารถใช้คุณลักษณะนี้ได้หากจำเป็น
เช่นเดียวกับรายการที่เชื่อมโยงเป็นทวีคูณซึ่งสามารถใช้การเชื่อมโยง XOr เพื่อลดพื้นที่ใช้งานได้อย่างมาก อีกครั้งนี้เป็นไปไม่ได้กับ Qt เนื่องจากเป็นข้อกำหนดสำหรับการเติบโตและ COW
COW สามารถทำให้บางสิ่งบางอย่างเบาลงได้ แต่เช่น Intrusive Containers เช่นการสนับสนุนโดยการเพิ่มและ Qt ใช้สิ่งเหล่านี้บ่อยครั้งในรุ่นก่อนหน้า แต่พวกมันไม่ได้ใช้มากนักเพราะมันยากที่จะใช้ไม่ปลอดภัยและกำหนดภาระ บนโปรแกรมเมอร์ วัวเป็นทางออกที่รบกวนน้อยกว่า แต่ไม่น่าสนใจด้วยเหตุผลที่กล่าวมาข้างต้น
ไม่มีเหตุผลใดที่คุณไม่สามารถใช้คอนเทนเนอร์ STL ที่มีหน่วยความจำเท่ากันหรือน้อยกว่าตู้คอนเทนเนอร์ของ Qt โดยมีข้อดีเพิ่มเติมคือการรู้ว่าคุณจะต้องใช้หน่วยความจำเท่าใดในเวลาใดก็ตาม เป็นไปไม่ได้ที่จะเปรียบเทียบทั้งสองในการใช้หน่วยความจำดิบเนื่องจากมาตรฐานดังกล่าวจะแสดงผลลัพธ์ที่แตกต่างกันอย่างมากในกรณีการใช้งานที่แตกต่างกันซึ่งเป็นปัญหาที่แน่นอนที่ STL ถูกออกแบบมาเพื่อแก้ไข
สรุปแล้ว
หลีกเลี่ยงการใช้ Qt Containers เมื่อเป็นไปได้โดยไม่ต้องเสียค่าใช้จ่ายในการคัดลอกและใช้การทำซ้ำชนิด STL (อาจผ่านตัวหุ้มหรือไวยากรณ์ใหม่) ทุกครั้งที่ทำได้