ตัวเลือกระหว่าง vector :: resize () และ vector :: Reserve ()


151

ฉันจัดสรรหน่วยความจำล่วงหน้าให้กับvectorตัวแปรสมาชิกของฉัน รหัสด้านล่างเป็นส่วนที่น้อยที่สุด

class A {
  vector<string> t_Names;
public:
  A () : t_Names(1000) {}
};

ตอนนี้ในบางจุดของเวลาถ้าเท่ากับt_Names.size() ฉันกำลังมีความประสงค์ที่จะเพิ่มขนาดโดย1000 100จากนั้นถ้ามันถึง1100ให้เพิ่มอีกครั้ง100และอื่น ๆ

คำถามของฉันคือสิ่งที่ต้องเลือกระหว่างและvector::resize() vector::reserve()มีทางเลือกที่ดีกว่าในสถานการณ์ประเภทนี้หรือไม่?

แก้ไข : t_Namesฉันมีการเรียงลำดับของการประมาณการที่แม่นยำสำหรับ เราคาดว่าจะเป็นรอบที่จะ700 800อย่างไรก็ตามในบาง (ไม่ค่อย) 1000สถานการณ์ก็สามารถเจริญเติบโตได้มากกว่า


34
คุณตระหนักว่าการทำเช่นนี้หมายถึงว่าการเติบโตของเวกเตอร์จะไม่ตัดจำหน่ายเวลาคงstd::vectorและคุณเสียหนึ่งในผลประโยชน์ของการใช้
Blastfurnace

1
jww

คำตอบ:


262

ฟังก์ชั่นทั้งสองทำสิ่งที่แตกต่างอย่างมากมาย!

resize()วิธี (และผ่านอาร์กิวเมนต์นวกรรมิกเทียบเท่ากับที่) จะแทรกหรือลบจำนวนที่เหมาะสมขององค์ประกอบเวกเตอร์ที่จะทำให้มันได้รับขนาด (มันมีอาร์กิวเมนต์ที่สองตัวเลือกที่จะระบุค่าของพวกเขา) มันจะส่งผลกระทบต่อการsize()ทำซ้ำจะไปที่องค์ประกอบเหล่านั้นทั้งหมด push_back จะแทรกหลังจากพวกเขาและคุณสามารถเข้าถึงพวกเขาโดยตรงโดยใช้operator[]จะแทรกหลังจากที่พวกเขาและคุณโดยตรงสามารถเข้าถึงได้โดยใช้

reserve()วิธีเดียวที่จัดสรรหน่วยความจำ แต่ใบมันเตรียม มันมีผลต่อเท่านั้นcapacity()แต่size()จะไม่เปลี่ยนแปลง ไม่มีค่าสำหรับวัตถุเนื่องจากไม่มีการเพิ่มอะไรเข้าไปในเวกเตอร์ ถ้าคุณใส่องค์ประกอบแล้วจะไม่มีการจัดสรรใหม่เกิดขึ้นเพราะมันทำล่วงหน้า แต่นั่นเป็นผลกระทบเท่านั้น

ดังนั้นมันขึ้นอยู่กับสิ่งที่คุณต้องการ หากคุณต้องการอาร์เรย์ของ 1000 resize()รายการเริ่มต้นของการใช้งาน หากคุณต้องการอาร์เรย์ที่คุณคาดว่าจะแทรก 1,000 รายการและต้องการหลีกเลี่ยงการจัดสรรสองสามรายการให้ใช้reserve()รายการและต้องการที่จะหลีกเลี่ยงคู่ของการจัดสรรหนึ่งใช้

แก้ไข:ความคิดเห็นของ Blastfurnace ทำให้ฉันอ่านคำถามอีกครั้งและตระหนักว่าในกรณีของคุณคำตอบที่ถูกต้องไม่ได้ถูกจัดสรรล่วงหน้าด้วยตนเอง เพียงแค่แทรกองค์ประกอบในตอนท้ายตามที่คุณต้องการ เวกเตอร์จะจัดสรรโดยอัตโนมัติตามความจำเป็นและจะทำมันได้มากขึ้นได้อย่างมีประสิทธิภาพกว่าคู่มือวิธีที่กล่าวถึง กรณีเดียวที่reserve()เหมาะสมคือเมื่อคุณมีการประมาณขนาดโดยรวมที่แม่นยำอย่างสมเหตุสมผลคุณจะต้องใช้งานได้ล่วงหน้าอย่างง่ายดาย

EDIT2: การแก้ไขคำถามโฆษณา: หากคุณมีการประมาณการเบื้องต้นแสดงreserve()ว่าการประมาณการนั้น ถ้ามันยังไม่พอเพียงให้เวกเตอร์ทำมัน


ฉันแก้ไขคำถามแล้ว vectorฉันจะมีการประมาณการบางอย่างสำหรับการ
iammilind

3
@Jan: ดีมันเปราะบางหรือไม่ตามความยากลำบากที่คุณได้ทำเพื่อตัวเองในการรักษาทรัพย์สินที่ต้องการ บางสิ่งที่คล้ายกันx.reserve(x.size() + newdata); vector<int>::iterator special_element = get_special_element(x); for (int i = 0; i < newdata; ++i) { if some_function(i, special_element) x.push_back(i); }นั้นแข็งแกร่งพอ ๆ กับการจองพื้นที่ที่เกี่ยวข้อง ฉันไม่ทราบว่าจะมีการเพิ่มองค์ประกอบกี่รายการ แต่ฉันมีขอบเขตบน แน่นอนเมื่อมีข้อสงสัยเวกเตอร์ที่คุณสามารถใช้ดัชนีแทนตัววนซ้ำความแตกต่างมักจะเล็กน้อย
Steve Jessop

4
ถ้อยคำของคุณเหมาะสมกับคนที่รู้คำตอบที่ถูกต้องอยู่แล้ว แต่อาจทำให้คนเข้าใจผิดต้องถามคำถาม "resize () ... จะแทรกจำนวนองค์ประกอบที่กำหนดให้กับเวกเตอร์" - เฉพาะจริงในครั้งแรกที่ใช้ - โดยทั่วไปจะแทรกความแตกต่างระหว่างหมายเลขที่ร้องขอและที่มีอยู่size()ก่อน "เมธอด Reserve () จัดสรรหน่วยความจำเท่านั้น" - อาจจัดสรรหน่วยความจำได้หรือไม่ขึ้นอยู่กับว่าcapacity()มีเพียงพอแล้วหรือยังอาจต้องย้ายองค์ประกอบและจัดสรรคืนหน่วยความจำดั้งเดิม "ต้องการหลีกเลี่ยงการจัดสรรสองสามครั้ง" และคัดลอก ฯลฯ
Tony Delroy

19
ที่จริงแล้วการสำรองก่อนผลักมีความสำคัญและต้องใช้ สมมติว่าคุณกำลังเขียนโค้ดตัวสร้างแบบจำลอง 3 มิติบางประเภทและโมเดลมีจุดยอดประมาณ 15,000 จุด หากคุณพยายามที่จะ push_back แต่ละจุดยอดในขณะที่โหลดโดยไม่ทำการจัดสรรล่วงหน้าก่อนมันจะใช้เวลานาน ฉันพบว่าตัวเองพยายามโหลดรถ. obj ที่มีจุดสูงสุดเกือบ 100,000 อันใช้เวลา 30 วินาที จากนั้นฉันปรับโครงสร้างโค้ดอีกครั้งโดยใช้การจัดสรรล่วงหน้าด้วย .reserve () ตอนนี้ใช้เวลา 3 วินาที เพียงใส่ .reserve (100000) ในตอนต้นของรหัสที่บันทึกไว้ 27 วินาที
deniz

1
@deniz นั้นเป็นเรื่องจริงเล็กน้อยที่ระดับ 100,000 แต่ไม่เป็นความจริงที่ระดับ 100-300 ซึ่งการสำรองอาจสิ้นเปลืองหากทำโดยไม่จำเป็น
deworde

30

resize()ไม่เพียง แต่จะจัดสรรหน่วยความจำก็ยังสร้างเป็นหลายกรณีเป็นที่ต้องการขนาดที่คุณส่งผ่านไปยังresize()เป็นอาร์กิวเมนต์ แต่reserve()จัดสรรหน่วยความจำเท่านั้นมันไม่ได้สร้างอินสแตนซ์ นั่นคือ,

std::vector<int> v1;
v1.resize(1000); //allocation + instance creation
cout <<(v1.size() == 1000)<< endl;   //prints 1
cout <<(v1.capacity()==1000)<< endl; //prints 1

std::vector<int> v2;
v2.reserve(1000); //only allocation
cout <<(v2.size() == 1000)<< endl;   //prints 0
cout <<(v2.capacity()==1000)<< endl; //prints 1

เอาท์พุท ( การสาธิตออนไลน์ ):

1
1
0
1

ดังนั้นresize()อาจไม่เป็นที่ต้องการหากคุณไม่ต้องการให้วัตถุที่สร้างขึ้นเป็นค่าเริ่มต้น มันจะช้าเช่นกัน นอกจากนี้หากคุณpush_back()องค์ประกอบใหม่ไปsize()เวกเตอร์ของจะเพิ่มขึ้นอีกโดยการจัดสรรหน่วยความจำใหม่ (ซึ่งหมายถึงการย้ายองค์ประกอบที่มีอยู่ไปยังพื้นที่หน่วยความจำที่จัดสรรใหม่) ถ้าคุณได้ใช้reserve()ที่เริ่มต้นเพื่อให้แน่ใจว่ามีหน่วยความจำแล้วจัดสรรพอsize()ของเวกเตอร์จะเพิ่มขึ้นเมื่อคุณpush_back()กับมันแต่มันจะไม่จัดสรรหน่วยความจำใหม่อีกครั้งจนกว่าจะวิ่งออกไปจากพื้นที่ที่คุณสงวนไว้สำหรับมัน


6
หลังจากทำเสร็จreserve(N)แล้วเราสามารถใช้อย่างoperator []ไม่เป็นอันตราย ถูกต้องไหม
iammilind

2
ในขณะที่การนำไปใช้งานส่วนใหญ่จะจัดสรรจำนวนเงินที่แน่นอนที่คุณร้องขอreserveข้อมูลจำเพาะนั้นต้องการให้จัดสรรอย่างน้อยที่สุดดังนั้นการใช้งานบางอย่างอาจปัดเศษเป็นขอบเขตและแสดงกำลังการผลิตที่สูงกว่า 1,000
Jan Hudec

16
@iammilind: v.size()ไม่มีหากดัชนีมีค่ามากกว่าหรือเท่ากับ โปรดทราบว่าreserve(N)จะไม่เปลี่ยนsize()เวกเตอร์
Nawaz

5
@iammilind: แก้ไขไม่ถูก หลังจากเรียก reSERVE จะไม่มีการเพิ่มรายการหน่วยความจำเพียงพอสำหรับการเพิ่มจะได้รับ
Jan Hudec

2

จากคำอธิบายของคุณดูเหมือนว่าคุณต้องการ "จอง" พื้นที่เก็บข้อมูลที่จัดสรรของเวกเตอร์ t_Names

รับทราบว่าresizeเริ่มต้นเวกเตอร์ที่จัดสรรใหม่ซึ่งreserveเพิ่งจัดสรร แต่ไม่สร้าง ดังนั้น 'สำรอง' จึงเร็วกว่า 'ปรับขนาด' มาก

คุณสามารถอ้างถึงเอกสารเกี่ยวกับความแตกต่างของการปรับขนาดและการจอง


1
โปรดดูรายละเอียดที่นี่แทน: เวกเตอร์และความจุ ( ทำไม )
sehe

1
ขอบคุณสำหรับการเพิ่มลิงค์, sehe
dip

2

สำรองเมื่อคุณไม่ต้องการให้วัตถุเริ่มต้นเมื่อจองไว้ นอกจากนี้คุณอาจต้องการแยกความแตกต่างเชิงตรรกะและติดตามจำนวนเมื่อเทียบกับจำนวนการใช้เมื่อคุณปรับขนาด ดังนั้นจึงมีความแตกต่างด้านพฤติกรรมในอินเทอร์เฟซ - เวกเตอร์จะแสดงจำนวนองค์ประกอบเท่ากันเมื่อสงวนไว้และจะมีขนาดใหญ่กว่า 100 องค์ประกอบเมื่อปรับขนาดในสถานการณ์ของคุณ

มีทางเลือกที่ดีกว่าในสถานการณ์ประเภทนี้หรือไม่?

มันขึ้นอยู่กับเป้าหมายของคุณเมื่อต่อสู้กับพฤติกรรมเริ่มต้น บางคนจะชื่นชอบการจัดสรรแบบกำหนดเอง - แต่เราต้องการแนวคิดที่ดีกว่าว่าคุณพยายามแก้ไขอะไรในโปรแกรมของคุณเพื่อให้คำแนะนำคุณได้ดี

fwiw, การใช้เวกเตอร์จำนวนมากจะเพิ่มจำนวนการจัดสรรองค์ประกอบสองเท่าเมื่อพวกเขาต้องเติบโต - คุณพยายามที่จะลดขนาดการจัดสรรสูงสุดหรือคุณพยายามที่จะจองพื้นที่เพียงพอสำหรับโปรแกรมล็อคฟรีหรืออย่างอื่น?


" สำรองเมื่อคุณไม่ต้องการวัตถุที่จะเริ่มต้นเมื่อ reserved. " สูตรที่ถูกต้องคือเมื่อคุณไม่ต้องการวัตถุที่มีอยู่ มันไม่เหมือนอาเรย์ที่ไม่ได้เตรียมไว้สำหรับประเภทที่สร้างขึ้นได้เล็กน้อยซึ่งไม่สามารถอ่านออบเจ็กต์ได้ แต่สามารถกำหนดให้ ค่อนข้างจะสงวนเฉพาะหน่วยความจำ แต่ไม่มีวัตถุอยู่ในนั้นดังนั้นจึงไม่สามารถเข้าถึงได้โดยใช้operator[]หรืออะไรก็ตาม
underscore_d
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.