มีรูปภาพที่รู้จักกันดี (ข้อมูลโกง) ที่เรียกว่า "C ++ Container choice" เป็นผังงานเพื่อเลือกภาชนะที่ดีที่สุดสำหรับการใช้งานที่ต้องการ
มีใครรู้บ้างว่ามีเวอร์ชัน C ++ 11 อยู่แล้วหรือไม่?
นี่คือรายการก่อนหน้า:
มีรูปภาพที่รู้จักกันดี (ข้อมูลโกง) ที่เรียกว่า "C ++ Container choice" เป็นผังงานเพื่อเลือกภาชนะที่ดีที่สุดสำหรับการใช้งานที่ต้องการ
มีใครรู้บ้างว่ามีเวอร์ชัน C ++ 11 อยู่แล้วหรือไม่?
นี่คือรายการก่อนหน้า:
คำตอบ:
ไม่ใช่ว่าฉันรู้ แต่มันสามารถทำได้ตามข้อความฉันเดา นอกจากนี้แผนภูมิยังดับเล็กน้อยเนื่องจากlist
โดยทั่วไปไม่ใช่คอนเทนเนอร์ที่ดีและไม่เป็นforward_list
เช่นนั้น ทั้งสองรายการเป็นคอนเทนเนอร์พิเศษสำหรับการใช้งานเฉพาะกลุ่ม
ในการสร้างแผนภูมิดังกล่าวคุณต้องมีแนวทางง่ายๆสองข้อ:
การกังวลเกี่ยวกับประสิทธิภาพมักจะไร้ประโยชน์ในตอนแรก การพิจารณา O ครั้งใหญ่จะเกิดขึ้นเมื่อคุณเริ่มจัดการรายการไม่กี่พัน (หรือมากกว่า) เท่านั้น
ตู้คอนเทนเนอร์มีสองประเภทใหญ่ ๆ :
find
ดำเนินการstack
และจากนั้นคุณสามารถสร้างอะแดปเตอร์หลายด้านบนของพวกเขา queue
, priority_queue
, ฉันจะทิ้งอะแดปเตอร์ไว้ที่นี่เนื่องจากมีความเชี่ยวชาญเพียงพอที่จะจดจำได้
คำถามที่ 1: Associative ?
คำถาม 1.1: สั่งซื้อ ?
unordered_
คอนเทนเนอร์หรือใช้คำสั่งซื้อแบบดั้งเดิมคำถาม 1.2: แยกคีย์ ?
map
หรือใช้ aset
คำถามที่ 1.3: ซ้ำกัน ?
multi
มิฉะนั้นอย่าทำตัวอย่าง:
สมมติว่าฉันมีบุคคลหลายคนที่มี ID เฉพาะที่เกี่ยวข้องกับพวกเขาและฉันต้องการดึงข้อมูลบุคคลจาก ID ของบุคคลนั้นให้ง่ายที่สุด
ฉันต้องการfind
ฟังก์ชันจึงเป็นคอนเทนเนอร์ที่เชื่อมโยงกัน
1.1. ฉันไม่สนใจคำสั่งซื้อน้อยลงดังนั้นunordered_
คอนเทนเนอร์
1.2. คีย์ (ID) ของฉันแยกจากค่าที่เกี่ยวข้องดังนั้นจึงเป็นmap
1.3. ID ไม่ซ้ำกันจึงไม่ควรเล็ดลอดเข้ามาซ้ำ
คำตอบสุดท้ายคือ: std::unordered_map<ID, PersonData>
.
คำถามที่ 2: หน่วยความจำเสถียรหรือไม่?
list
คำถาม 2.1: ไหน ?
list
; a forward_list
มีประโยชน์สำหรับหน่วยความจำที่น้อยลงเท่านั้นคำถามที่ 3: ขนาดแบบไดนามิก ?
{ ... }
ไวยากรณ์) จากนั้นใช้array
. แทนที่ C-array แบบเดิม แต่มีฟังก์ชันที่สะดวกคำถามที่ 4: Double-ended ?
deque
หรือใช้ a vector
.vector
คุณจะทราบว่าโดยปกติถ้าคุณต้องการภาชนะที่สมาคมทางเลือกของคุณจะเป็น มันจะเปิดออกก็ยังเป็นซัทเทอและ Stroustrup ของคำแนะนำ
array
ไม่ต้องการประเภทที่สร้างได้เริ่มต้น 2) การเลือกรายการmulti
นั้นไม่มากเกี่ยวกับการอนุญาตให้ทำซ้ำแต่ข้อมูลเพิ่มเติมเกี่ยวกับว่าการเก็บข้อมูลเหล่านี้มีความสำคัญหรือไม่ (คุณสามารถใส่รายการที่ซ้ำกันในmulti
คอนเทนเนอร์ที่ไม่ใช่คอนเทนเนอร์ได้ แต่ก็เกิดขึ้นที่มีเพียงรายการเดียวเท่านั้นที่ถูกเก็บไว้)
map.find(key)
เป็นที่พอใจมากขึ้นกว่าstd::find(map.begin(), map.end(), [&](decltype(map.front()) p) { return p.first < key; }));
แต่ดังนั้นจึงเป็นสิ่งที่สำคัญความหมายว่าเป็นหน้าที่ของสมาชิกมากกว่าหนึ่งจากfind
<algorithm>
สำหรับ O (1) กับ O (log n) จะไม่มีผลต่อความหมาย ฉันจะลบ "ประสิทธิภาพ" ออกจากตัวอย่างและแทนที่ด้วย "อย่างง่ายดาย"
deque
มีคุณสมบัตินี้ด้วยเหรอ?
deque
องค์ประกอบจะคงที่ก็ต่อเมื่อคุณดัน / ป๊อปที่ปลายด้านใดด้านหนึ่ง หากคุณเริ่มแทรก / ลบตรงกลางองค์ประกอบสูงสุด N / 2 จะถูกสับเพื่อเติมช่องว่างที่สร้างขึ้น
ฉันชอบคำตอบของ Matthieu แต่ฉันจะสร้างผังงานใหม่เป็นดังนี้:
std::vector
โดยค่าเริ่มต้นถ้าคุณต้องการภาชนะของสิ่งที่ใช้ ดังนั้นคอนเทนเนอร์อื่น ๆ ทั้งหมดจึงมีเหตุผลโดยการให้ฟังก์ชันทางเลือกบางอย่างstd::vector
เท่านั้น
std::vector
ต้องการให้เนื้อหาเคลื่อนย้ายได้เนื่องจากต้องสามารถสับเปลี่ยนรายการรอบ ๆ นี่ไม่ใช่ภาระที่น่ากลัวในการวางเนื้อหา (โปรดทราบว่าไม่จำเป็นต้องใช้ตัวสร้างเริ่มต้นขอบคุณemplace
และอื่น ๆ ) อย่างไรก็ตามคอนเทนเนอร์อื่น ๆ ส่วนใหญ่ไม่ต้องการตัวสร้างใด ๆ โดยเฉพาะ (ขอบคุณอีกครั้งemplace
) ดังนั้นหากคุณมีวัตถุที่คุณไม่สามารถใช้ตัวสร้างการย้ายได้อย่างแน่นอนคุณจะต้องเลือกอย่างอื่น
A std::deque
จะเป็นการแทนที่ทั่วไปโดยมีคุณสมบัติมากมายstd::vector
แต่คุณสามารถแทรกที่ปลายด้านใดด้านหนึ่งของ deque เท่านั้น เม็ดมีดตรงกลางต้องการการเคลื่อนย้าย std::list
สถานที่ต้องการไม่มีในเนื้อหา
std::vector<bool>
ไม่ใช่. มันเป็นมาตรฐาน แต่มันไม่ใช่vector
ในแง่ปกติเนื่องจากการดำเนินการที่std::vector
อนุญาตตามปกติเป็นสิ่งต้องห้าม และแน่นอนที่สุดไม่ได้มีbool
s
ดังนั้นถ้าคุณต้องการจริงvector
พฤติกรรมจากภาชนะของbool
s std::vector<bool>
คุณจะไม่ได้รับจาก ดังนั้นคุณจะต้องชำระเงินด้วยไฟล์std::deque<bool>
.
หากคุณต้องการที่จะหาองค์ประกอบในภาชนะและแท็กค้นหาไม่สามารถเพียงแค่เป็นดัชนีแล้วคุณอาจต้องละทิ้งstd::vector
ในความโปรดปรานของและset
map
สังเกตคำสำคัญ " may "; std::vector
บางครั้งการเรียงลำดับก็เป็นทางเลือกที่สมเหตุสมผล หรือ Boost.Container ของซึ่งการดำเนินการเรียงลำดับflat_set/map
std::vector
ตอนนี้มีสี่รูปแบบเหล่านี้แต่ละแบบมีความต้องการของตัวเอง
map
เมื่อแท็กค้นหาไม่ใช่สิ่งเดียวกับรายการที่คุณกำลังค้นหา มิฉะนั้นให้ใช้ไฟล์set
.unordered
เมื่อคุณมีจำนวนมากของรายการในภาชนะและค้นหาประสิทธิภาพอย่างจะต้องมีมากกว่าO(1)
O(logn)
multi
หากคุณต้องการหลายรายการเพื่อให้มีแท็กการค้นหาเดียวกันหากคุณต้องการให้มีการจัดเรียงตู้สินค้าตามการดำเนินการเปรียบเทียบโดยเฉพาะคุณสามารถใช้ไฟล์set
. หรือmulti_set
ถ้าคุณต้องการหลายรายการเพื่อให้มีมูลค่าเท่ากัน
หรือคุณสามารถใช้การจัดเรียงstd::vector
แต่คุณจะต้องจัดเรียงไว้
เมื่อตัวทำซ้ำและการอ้างอิงไม่ถูกต้องบางครั้งก็เป็นเรื่องที่น่ากังวล หากคุณต้องการรายการที่คุณมีตัวทำซ้ำ / ตัวชี้ไปยังรายการเหล่านั้นในที่อื่น ๆstd::vector
วิธีการที่จะทำให้ไม่ถูกต้องอาจไม่เหมาะสม การดำเนินการแทรกใด ๆ อาจทำให้ไม่ถูกต้องขึ้นอยู่กับขนาดและความจุปัจจุบัน
std::list
เสนอการรับประกันที่มั่นคง: ตัววนซ้ำและการอ้างอิง / ตัวชี้ที่เกี่ยวข้องจะไม่ถูกต้องก็ต่อเมื่อมีการนำไอเท็มออกจากคอนเทนเนอร์ std::forward_list
จะมีไหมหากความทรงจำเป็นปัญหาร้ายแรง
หากการรับประกันนั้นแข็งแกร่งเกินไปให้เสนอการรับประกันstd::deque
ที่อ่อนแอกว่า แต่มีประโยชน์ การไม่ตรวจสอบเป็นผลมาจากการแทรกที่อยู่ตรงกลาง แต่การแทรกที่ส่วนหัวหรือส่วนท้ายทำให้เกิดการไม่ถูกต้องของตัวทำซ้ำเท่านั้นไม่ใช่ตัวชี้ / การอ้างอิงไปยังรายการในคอนเทนเนอร์
std::vector
ให้การแทรกราคาถูกในตอนท้ายเท่านั้น (และถึงแม้จะมีราคาแพงหากคุณเป่าความจุ)
std::list
มีราคาแพงในแง่ของประสิทธิภาพ (แต่ละรายการแทรกใหม่ค่าใช้จ่ายในการจัดสรรหน่วยความจำ) แต่มันเป็นเรื่องที่สอดคล้องกัน นอกจากนี้ยังมีความสามารถที่ขาดไม่ได้ในบางครั้งในการสับเปลี่ยนไอเท็มรอบ ๆ โดยแทบจะไม่มีต้นทุนด้านประสิทธิภาพอีกทั้งยังสามารถแลกเปลี่ยนสินค้ากับstd::list
คอนเทนเนอร์ประเภทเดียวกันได้โดยไม่สูญเสียประสิทธิภาพ หากคุณจำเป็นต้องสับเปลี่ยนสิ่งรอบ ๆจำนวนมากstd::list
ใช้
std::deque
ให้การแทรก / ถอดที่หัวและท้ายตลอดเวลา แต่การแทรกตรงกลางอาจมีราคาแพงพอสมควร ดังนั้นหากคุณต้องการเพิ่ม / ลบสิ่งต่างๆจากด้านหน้าและด้านหลังstd::deque
อาจเป็นสิ่งที่คุณต้องการ
ควรสังเกตว่าด้วยการย้ายความหมายstd::vector
ประสิทธิภาพการแทรกอาจไม่เลวร้ายอย่างที่เคยเป็น การใช้งานบางอย่างใช้รูปแบบของการคัดลอกรายการที่อิงตามความหมาย (หรือที่เรียกว่า "swaptimization") แต่ตอนนี้การย้ายนั้นเป็นส่วนหนึ่งของภาษามันได้รับคำสั่งจากมาตรฐาน
std::array
เป็นคอนเทนเนอร์ที่ดีหากคุณต้องการการจัดสรรแบบไดนามิกน้อยที่สุดเท่าที่จะเป็นไปได้ มันเป็นเพียงกระดาษห่อหุ้มรอบ C-array ที่นี้หมายถึงว่าขนาดของมันจะต้องรู้จักที่รวบรวมเวลา std::array
หากคุณสามารถอยู่กับที่แล้วใช้
ที่ถูกกล่าวว่าการใช้std::vector
และreserve
ไอเอ็นจีขนาดจะทำงานได้เป็นอย่างดีสำหรับ std::vector
bounded ด้วยวิธีนี้ขนาดจริงอาจแตกต่างกันไปและคุณจะได้รับการจัดสรรหน่วยความจำเพียงชุดเดียว (เว้นแต่คุณจะเพิ่มขีดความสามารถ)
std::sort
นี้ยังมีสิ่งstd::inplace_merge
ที่น่าสนใจในการวางองค์ประกอบใหม่ ๆ ได้อย่างง่ายดาย (แทนที่จะเป็นstd::lower_bound
+ std::vector::insert
โทร) ยินดีที่ได้เรียนรู้flat_set
และflat_map
!
vector<bool>
vector<char>
std::allocator<T>
ไม่รองรับการจัดแนวนั้น (และฉันไม่รู้ว่าทำไมจึงไม่) คุณสามารถใช้ตัวจัดสรรที่กำหนดเองได้ตลอดเวลา
std::vector::resize
มีโอเวอร์โหลดที่ไม่ใช้ค่า (ใช้ขนาดใหม่เท่านั้นองค์ประกอบใหม่ใด ๆ จะถูกสร้างขึ้นตามค่าเริ่มต้น) นอกจากนี้เหตุใดคอมไพเลอร์จึงไม่สามารถจัดแนวพารามิเตอร์ค่าได้อย่างถูกต้องแม้ว่าจะมีการประกาศว่ามีการจัดแนวก็ตาม
bitset
สำหรับบูลหากคุณทราบขนาดล่วงหน้าen.cppreference.com/w/cpp/utility/bitset
นี่คือผังงานด้านบนเวอร์ชัน C ++ 11 [โพสต์ครั้งแรกโดยไม่มีการระบุแหล่งที่มาของผู้เขียนต้นฉบับMikael Persson ]
นี่เป็นการหมุนอย่างรวดเร็วแม้ว่าอาจต้องใช้งาน
Should the container let you manage the order of the elements?
Yes:
Will the container contain always exactly the same number of elements?
Yes:
Does the container need a fast move operator?
Yes: std::vector
No: std::array
No:
Do you absolutely need stable iterators? (be certain!)
Yes: boost::stable_vector (as a last case fallback, std::list)
No:
Do inserts happen only at the ends?
Yes: std::deque
No: std::vector
No:
Are keys associated with Values?
Yes:
Do the keys need to be sorted?
Yes:
Are there more than one value per key?
Yes: boost::flat_map (as a last case fallback, std::map)
No: boost::flat_multimap (as a last case fallback, std::map)
No:
Are there more than one value per key?
Yes: std::unordered_multimap
No: std::unordered_map
No:
Are elements read then removed in a certain order?
Yes:
Order is:
Ordered by element: std::priority_queue
First in First out: std::queue
First in Last out: std::stack
Other: Custom based on std::vector?????
No:
Should the elements be sorted by value?
Yes: boost::flat_set
No: std::vector
คุณอาจพบว่ามีความแตกต่างอย่างดุเดือดจากซี ++ 03 รุ่นหลักเนื่องจากความจริงที่ว่าผมไม่ชอบโหนดที่เชื่อมโยง โดยปกติคอนเทนเนอร์โหนดที่เชื่อมโยงสามารถเอาชนะประสิทธิภาพได้โดยคอนเทนเนอร์ที่ไม่ได้เชื่อมโยงยกเว้นในบางสถานการณ์ที่เกิดขึ้นได้ยาก หากคุณไม่รู้ว่าสถานการณ์เหล่านั้นคืออะไรและสามารถเข้าถึงบูสต์ได้อย่าใช้คอนเทนเนอร์โหนดที่เชื่อมโยง (std :: list, std :: slist, std :: map, std :: multimap, std :: set, std :: multiset) รายการนี้เน้นที่คอนเทนเนอร์ขนาดเล็กและขนาดกลางเป็นส่วนใหญ่เนื่องจาก (A) เป็น 99.99% ของสิ่งที่เราจัดการในโค้ดและ (B) องค์ประกอบจำนวนมากต้องการอัลกอริทึมที่กำหนดเองไม่ใช่คอนเทนเนอร์ที่แตกต่าง