ตั้งแต่
- ทั้งคู่เป็นคอนเทนเนอร์หน่วยความจำที่ต่อเนื่องกัน
- คุณลักษณะที่ชาญฉลาด deque มีเวกเตอร์เกือบทุกอย่าง แต่มีมากกว่านั้นเนื่องจากการแทรกที่ด้านหน้ามีประสิทธิภาพ
ทำไมทุกคน Whould ต้องการstd::vector
เพื่อstd::deque
?
ตั้งแต่
ทำไมทุกคน Whould ต้องการstd::vector
เพื่อstd::deque
?
คำตอบ:
องค์ประกอบในdeque
มีความไม่ต่อเนื่องกันในหน่วยความจำ vector
องค์ประกอบได้รับการประกันว่าเป็น ดังนั้นหากคุณต้องการที่จะมีปฏิสัมพันธ์กับห้องสมุด C ธรรมดาที่ต้องการอาร์เรย์ที่ต่อเนื่องกันหรือถ้าคุณสนใจ (มาก) vector
เกี่ยวกับท้องที่อวกาศแล้วคุณอาจจะชอบ นอกจากนี้เนื่องจากมีการทำบัญชีพิเศษบางหน่วยงานอื่น ๆ อาจมีราคาแพงกว่าvector
การดำเนินการที่เทียบเท่ากัน (เล็กน้อย) ในทางกลับกันการใช้อินสแตนซ์จำนวนมาก / จำนวนมากvector
อาจทำให้เกิดการกระจายตัวของฮีปโดยไม่จำเป็น (ทำให้การโทรช้าลงnew
)
นอกจากนี้ยังเป็นแหลมออกอื่น ๆ ใน StackOverflowมีการสนทนาที่ดีอื่น ๆ อีกมากมายที่นี่: http://www.gotw.ca/gotw/054.htm
หากต้องการทราบความแตกต่างเราควรทราบวิธีdeque
การนำไปใช้โดยทั่วไป หน่วยความจำถูกจัดสรรเป็นบล็อกที่มีขนาดเท่ากันและจะถูกรวมเข้าด้วยกัน (เป็นอาร์เรย์หรืออาจเป็นเวกเตอร์)
ดังนั้นหากต้องการค้นหาองค์ประกอบที่ n คุณจะพบบล็อกที่เหมาะสมจากนั้นเข้าถึงองค์ประกอบที่อยู่ภายในนั้น นี่เป็นเวลาคงที่เพราะมันมักจะค้นหา 2 ครั้ง แต่นั่นก็ยังมากกว่าเวกเตอร์
vector
ยังทำงานได้ดีกับ API ที่ต้องการบัฟเฟอร์ที่ต่อเนื่องกันเนื่องจากเป็น C API หรือมีความหลากหลายมากกว่าในการใช้ตัวชี้และความยาว (ดังนั้นคุณสามารถมีเวกเตอร์อยู่ข้างใต้หรืออาร์เรย์ปกติและเรียก API จากบล็อกหน่วยความจำของคุณ)
ในกรณีที่deque
มีข้อได้เปรียบที่ใหญ่ที่สุดคือ:
อย่างที่สองเป็นที่รู้จักน้อยกว่า แต่สำหรับคอลเลกชันขนาดใหญ่มาก:
เมื่อฉันจัดการกับคอลเลกชันขนาดใหญ่ในอดีตและย้ายจากโมเดลที่ต่อเนื่องกันไปเป็นโมเดลบล็อกเราสามารถจัดเก็บคอลเลคชันขนาดใหญ่ได้ประมาณ 5 เท่าก่อนที่หน่วยความจำจะหมดในระบบ 32 บิต ส่วนหนึ่งเป็นเพราะเมื่อทำการจัดสรรใหม่จำเป็นต้องจัดเก็บบล็อกเก่าและบล็อกใหม่ก่อนที่จะคัดลอกองค์ประกอบ
เมื่อพูดทั้งหมดนี้คุณอาจมีปัญหากับstd::deque
ระบบที่ใช้การจัดสรรหน่วยความจำแบบ "มองโลกในแง่ดี" ในขณะที่ความพยายามที่จะขอขนาดบัฟเฟอร์ขนาดใหญ่สำหรับการจัดสรรใหม่ของ a vector
อาจจะถูกปฏิเสธในบางจุดด้วย a bad_alloc
ลักษณะที่มองโลกในแง่ดีของผู้จัดสรรมักจะให้การร้องขอสำหรับบัฟเฟอร์ขนาดเล็กที่ร้องขอโดย a deque
และมีแนวโน้มที่จะก่อให้เกิด ระบบปฏิบัติการจะฆ่ากระบวนการเพื่อพยายามรับหน่วยความจำบางส่วน เลือกอันไหนก็อาจจะไม่ถูกใจนัก
วิธีแก้ปัญหาในกรณีดังกล่าว ได้แก่ การตั้งค่าแฟล็กระดับระบบเพื่อลบล้างการจัดสรรในแง่ดี (ไม่สามารถทำได้เสมอไป) หรือจัดการหน่วยความจำด้วยตนเองค่อนข้างมากขึ้นเช่นการใช้ตัวจัดสรรของคุณเองที่ตรวจสอบการใช้หน่วยความจำหรือสิ่งที่คล้ายกัน เห็นได้ชัดว่าไม่เหมาะอย่างยิ่ง (ซึ่งอาจตอบคำถามของคุณได้ว่าชอบเวกเตอร์ ... )
ฉันใช้ทั้ง vector และ deque หลายครั้งแล้ว deque มีความซับซ้อนมากขึ้นอย่างมากจากมุมมองของการนำไปใช้งาน ความซับซ้อนนี้แปลเป็นรหัสมากขึ้นและรหัสที่ซับซ้อนมากขึ้น ดังนั้นโดยทั่วไปคุณจะเห็นขนาดโค้ดเมื่อคุณเลือก deque ทับเวกเตอร์ นอกจากนี้คุณยังอาจได้รับการตีด้วยความเร็วเพียงเล็กน้อยหากโค้ดของคุณใช้เฉพาะสิ่งที่เวกเตอร์เก่งเท่านั้น
หากคุณต้องการคิวสองครั้ง deque คือผู้ชนะที่ชัดเจน แต่ถ้าคุณใช้ส่วนแทรกส่วนใหญ่แล้วลบที่ด้านหลังเวกเตอร์จะเป็นผู้ชนะที่ชัดเจน เมื่อคุณไม่แน่ใจให้ประกาศคอนเทนเนอร์ของคุณด้วย typedef (เพื่อให้ง่ายต่อการสลับไปมา) และวัดผล
vector
.) ฉันได้เขียนการดำเนินการเชื่อมโยงไปยังด้านล่างในคำตอบของฉัน สามารถทำได้เร็วพอ ๆ กับ a vector
แต่ใช้ได้อย่างกว้างขวางกว่ามาก (เช่นเมื่อทำการต่อคิวอย่างรวดเร็ว)
std::deque
ไม่ได้รับประกันหน่วยความจำต่อเนื่อง - และมักจะค่อนข้างช้ากว่าสำหรับการเข้าถึงแบบดัชนี โดยทั่วไปจะใช้ deque เป็น "รายการเวกเตอร์"
อ้างอิงจากhttp://www.cplusplus.com/reference/stl/deque/ "ซึ่งแตกต่างจากเวกเตอร์คือไม่รับประกันว่า deques จะมีองค์ประกอบทั้งหมดในสถานที่จัดเก็บที่ต่อเนื่องกันทำให้ไม่สามารถเข้าถึงได้อย่างปลอดภัยโดยใช้เลขคณิตตัวชี้"
Deques ซับซ้อนกว่าเล็กน้อยส่วนหนึ่งเป็นเพราะพวกเขาไม่จำเป็นต้องมีเค้าโครงหน่วยความจำที่ต่อเนื่องกัน หากคุณต้องการคุณสมบัตินั้นคุณไม่ควรใช้ deque
(ก่อนหน้านี้คำตอบของฉันแสดงให้เห็นถึงการขาดมาตรฐาน (จากแหล่งข้อมูลเดียวกันกับข้างต้น "deques อาจถูกนำไปใช้โดยไลบรารีเฉพาะในรูปแบบที่แตกต่างกัน") แต่จริงๆแล้วใช้กับประเภทข้อมูลไลบรารีมาตรฐานเท่านั้น)
std::deque
std::vector
ไม่น้อยกว่ามาตรฐาน ฉันไม่เชื่อว่าข้อกำหนดด้านความซับซ้อนstd::deque
จะเป็นไปตามที่จัดเก็บข้อมูลที่ต่อเนื่องกันได้
deque
ไม่สามารถรองรับกับพื้นที่เก็บข้อมูลที่ต่อเนื่องกันได้?
deque
กล่าวคือการแทรกที่ปลายจะไม่ทำให้การอ้างอิงถึงองค์ประกอบที่มีอยู่เป็นโมฆะ ข้อกำหนดนี้แสดงถึงหน่วยความจำที่ไม่ต่อเนื่อง
deque เป็นคอนเทนเนอร์ลำดับที่อนุญาตให้เข้าถึงองค์ประกอบโดยสุ่ม แต่ไม่รับประกันว่าจะมีพื้นที่จัดเก็บที่ต่อเนื่อง
ฉันคิดว่าเป็นความคิดที่ดีที่จะทำการทดสอบประสิทธิภาพของแต่ละกรณี และตัดสินใจโดยอาศัยการทดสอบนี้
ฉันชอบstd::deque
มากกว่าstd::vector
ในกรณีส่วนใหญ่
vector
คนต้องการ เราสามารถสรุปได้ว่าเหตุใดจึงไม่เป็นข้อพิสูจน์ การบอกว่าคุณชอบdeque
โดยไม่ทราบสาเหตุจากการทดสอบที่ไม่ระบุรายละเอียดไม่ใช่คำตอบ
คุณไม่ต้องการให้เวกเตอร์ลบล้างตามผลการทดสอบเหล่านี้ (พร้อมแหล่งที่มา)
แน่นอนคุณควรทดสอบในแอป / สภาพแวดล้อมของคุณ แต่โดยสรุป:
ข้อมูลเพิ่มเติมบางส่วนและหมายเหตุที่ควรพิจารณา Circular_buffer
ในแง่หนึ่งเวกเตอร์มักจะค่อนข้างเร็วกว่า deque หากคุณไม่ต้องการคุณสมบัติทั้งหมดของ deque ให้ใช้เวกเตอร์
ในทางกลับกันบางครั้งคุณทำคุณลักษณะจำเป็นซึ่งเวกเตอร์ไม่ได้ให้คุณในกรณีที่คุณต้องใช้ deque ตัวอย่างเช่นฉันขอท้าให้ทุกคนพยายามเขียนโค้ดนี้ใหม่โดยไม่ต้องใช้ deque และไม่ต้องแก้ไขอัลกอริทึมมหาศาล
push_back
และpop_back
การดำเนินการเดียวกันdeque<int>
นั้นเร็วกว่าvector<int>
การทดสอบของฉันอย่างน้อย 20% เสมอ(gcc กับ O3) ฉันเดาว่านั่นคือเหตุผลที่deque
เป็นตัวเลือกมาตรฐานสำหรับสิ่งต่างๆเช่นstd::stack
...
โปรดทราบว่าหน่วยความจำเวกเตอร์จะถูกจัดสรรใหม่เมื่ออาร์เรย์เติบโตขึ้น หากคุณมีตัวชี้ไปยังองค์ประกอบเวกเตอร์องค์ประกอบเหล่านั้นจะไม่ถูกต้อง
นอกจากนี้หากคุณลบองค์ประกอบตัวทำซ้ำจะไม่ถูกต้อง (แต่ไม่ใช่ "สำหรับ (อัตโนมัติ ... )")
แก้ไข: เปลี่ยน 'deque' เป็น 'vector'
std::deque
มีขนาดบล็อกสูงสุดที่เล็กมาก (~ 16 ไบต์ถ้าฉันจำได้ถูกต้องอาจเป็น 32) และด้วยเหตุนี้จึงทำงานได้ไม่ดีนักสำหรับแอปพลิเคชันที่สมจริง โดยdeque<T>
ที่sizeof(T) > 8
(หรือ 16 เป็นตัวเลขเล็ก ๆ ) มีลักษณะการทำงานเหมือนกับ avector<T*>
โดยที่แต่ละองค์ประกอบได้รับการจัดสรรแบบไดนามิก การใช้งานอื่น ๆdeque
ที่มีขนาดของบล็อกสูงสุดแตกต่างกันดังนั้นการเขียนโค้ดที่มีค่อนข้างลักษณะการทำงานเดียวกันบนแพลตฟอร์มที่แตกต่างเป็นเรื่องยากกับ