ทำไมฉันถึงต้องใช้ std :: get_tem Contemporary_buffer?


84

ควรใช้เพื่อวัตถุประสงค์std::get_temporary_bufferอะไร? Standard กล่าวต่อไปนี้:

รับตัวชี้ไปยังหน่วยเก็บข้อมูลที่เพียงพอสำหรับจัดเก็บวัตถุ T ที่อยู่ติดกันได้สูงสุด n ตัว

ฉันคิดว่าบัฟเฟอร์จะถูกจัดสรรบนสแต็ก แต่นั่นไม่เป็นความจริง ตามมาตรฐาน C ++ บัฟเฟอร์นี้ไม่ได้เกิดขึ้นชั่วคราว ฟังก์ชันนี้มีข้อดีอะไรบ้างเมื่อเทียบกับฟังก์ชันโกลบอล::operator newซึ่งไม่ได้สร้างอ็อบเจกต์ด้วย ฉันคิดถูกหรือไม่ที่ข้อความต่อไปนี้เทียบเท่า

int* x;
x = std::get_temporary_buffer<int>( 10 ).first;
x = static_cast<int*>( ::operator new( 10*sizeof(int) ) );

ฟังก์ชันนี้มีเฉพาะสำหรับน้ำตาลไวยากรณ์หรือไม่? ทำไมถึงมีtemporaryชื่อ?


มีการแนะนำกรณีการใช้งานหนึ่งกรณีในวารสารของดร. ด็อบบ์วันที่ 1 กรกฎาคม พ.ศ. 2539สำหรับการใช้อัลกอริทึม:

หากไม่สามารถจัดสรรบัฟเฟอร์ได้หรือมีขนาดเล็กกว่าที่ร้องขออัลกอริทึมยังคงทำงานได้อย่างถูกต้องเพียงแค่ช้าลงเท่านั้น


2
FYI std::get_temporary_bufferจะเลิกใช้งานใน C ++ 17
Deqing

1
@ เต๋อชิงใช่แล้ว นอกจากนี้ยังจะถูกลบออกใน C ++ 20 และด้วยเหตุผลที่ดี (ดังที่กล่าวไว้ด้านล่าง) ไปตามผู้ชม ..
Nikos

คำตอบ:


44

Stroustrup พูดใน"The C ++ Programming Language" ( §19.4.4 , SE):

แนวคิดก็คือว่าระบบอาจเก็บจำนวนของบัฟเฟอร์มีขนาดคงที่พร้อมสำหรับการจัดสรรอย่างรวดเร็วว่าขอพื้นที่สำหรับnวัตถุอาจให้พื้นที่สำหรับมากกว่าn อย่างไรก็ตามมันอาจให้ผลตอบแทนน้อยกว่าด้วยดังนั้นวิธีหนึ่งในการใช้get_temporary_buffer()คือการขอให้มาก ๆ ในแง่ดีจากนั้นใช้สิ่งที่เกิดขึ้นเพื่อให้มีอยู่
[... ] เนื่องจากget_temporary_buffer()อยู่ในระดับต่ำและมีแนวโน้มที่จะได้รับการปรับให้เหมาะสมสำหรับการจัดการบัฟเฟอร์ชั่วคราวจึงไม่ควรใช้เป็นทางเลือกใหม่หรือตัวจัดสรร :: จัดสรร ()สำหรับการได้รับพื้นที่เก็บข้อมูลระยะยาว

นอกจากนี้เขายังเริ่มต้นการแนะนำสองฟังก์ชันด้วย:

อัลกอริทึมมักต้องการพื้นที่ชั่วคราวเพื่อให้ทำงานได้อย่างยอมรับได้

... แต่ดูเหมือนจะไม่ได้ให้คำจำกัดความของชั่วคราวหรือระยะยาวที่ใดก็ได้

เล็ก ๆ น้อย ๆใน"จากคณิตศาสตร์ทั่วไปการเขียนโปรแกรม"กล่าวว่า Stepanov ให้ดำเนินการยึดปลอมในการออกแบบ STL เดิมอย่างไร:

ด้วยความประหลาดใจของเขาเขาค้นพบหลายปีต่อมาว่าผู้ค้ารายใหญ่ทั้งหมดที่ให้การใช้งาน STL ยังคงใช้การใช้งานที่เลวร้ายนี้ [... ]


12
ดูเหมือนว่าการใช้งาน VC ++ จะเป็นเพียงการโทรแบบวนซ้ำที่operator newมีอาร์กิวเมนต์น้อยลงเรื่อย ๆ จนกว่าการจัดสรรจะสำเร็จ ไม่มีการเพิ่มประสิทธิภาพพิเศษที่นั่น
jalf

9
เช่นเดียวกับ g ++ 4.5 - ดูเหมือนว่าจะมีเจตนาดี แต่ผู้ขายเพิกเฉย
Georg Fritzsche

4
ดูเหมือนว่าพวกเขาควรจะรวมฟังก์ชันนี้ไว้ในคลาสที่เรียกว่าcrazy_allocator
0xbadf00d

แต่เอาจริงเอาจังกันเถอะ - บางทีใคร ๆ ก็พอใจที่จะจัดสรรพื้นที่เก็บข้อมูลจำนวนมาก สิ่งที่เราสามารถทำได้คือขอให้ระบบเพื่อให้ได้ว่าจำนวนมากของการจัดเก็บ - get_temporary_bufferใช้ อย่างไรก็ตามหากเราได้รับน้อยกว่าจำนวนที่ร้องขอ (สิ่งที่น่าเสียดายจริงๆ) เราจะพยายามทำงานกับพื้นที่เก็บข้อมูลที่เรามีต่อไป อาจจะดีกว่าการตรวจจับbad_allocข้อยกเว้นที่เกิดจากความพยายามที่จะจัดสรรหน่วยความจำมากกว่าที่มีอยู่ อย่างไรก็ตามประโยชน์ที่แท้จริงนั้นเกิดขึ้นได้จากการนำไปใช้งานที่ดี
0xbadf00d

@jalf เลิกใช้แล้วใน C ++ 17 :) (อ้างอิงจากcppreference.com )
4LegsDrivenCat

17

ห้องสมุดมาตรฐานของ Microsoft กล่าวว่าสิ่งต่อไปนี้ ( ที่นี่ ):

  • คุณช่วยอธิบายได้ไหมว่าเมื่อใดควรใช้ 'get_tem Contemporary_buffer'

มีวัตถุประสงค์เฉพาะอย่างยิ่ง โปรดทราบว่าจะไม่ทิ้งข้อยกเว้นเช่นใหม่ (nothrow) แต่ยังไม่สร้างวัตถุซึ่งแตกต่างจากใหม่ (nothrow)

STL ใช้ภายในในอัลกอริทึมเช่น stable_partition () สิ่งนี้เกิดขึ้นเมื่อมีคำวิเศษเช่น N3126 25.3.13 [alg.partitions] / 11: stable_partition () มีความซับซ้อน "การแลกเปลี่ยนมากที่สุด (สุดท้าย - แรก) * บันทึก (ครั้งสุดท้าย - แรก) แต่จะมีจำนวนการแลกเปลี่ยนเชิงเส้นเท่านั้นหากมี ก็เพียงพอแล้ว " เมื่อคำวิเศษ "หากมีหน่วยความจำเพิ่มเติมเพียงพอ" ปรากฏขึ้น STL จะใช้ get_tem Contemporary_buffer () เพื่อพยายามหาพื้นที่ทำงาน หากทำได้ก็จะสามารถใช้อัลกอริทึมได้อย่างมีประสิทธิภาพมากขึ้น หากไม่สามารถทำได้เนื่องจากระบบกำลังทำงานอยู่ใกล้กับหน่วยความจำไม่เพียงพอ (หรือช่วงที่เกี่ยวข้องมีขนาดใหญ่มาก) อัลกอริทึมสามารถถอยกลับไปใช้เทคนิคที่ช้าลงได้

99.9% ของผู้ใช้ STL ไม่จำเป็นต้องรู้เกี่ยวกับ get_tem Contemporary_buffer ()


9

มาตรฐานระบุว่าจัดสรรพื้นที่เก็บข้อมูลได้สูงสุด nองค์ประกอบ กล่าวอีกนัยหนึ่งตัวอย่างของคุณอาจส่งคืนบัฟเฟอร์ที่ใหญ่พอสำหรับ 5 ออบเจ็กต์เท่านั้น

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

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


4

ฉันควรใช้เพื่อวัตถุประสงค์อะไร std::get_temporary_buffer?

ฟังก์ชันนี้เลิกใช้งานแล้วใน C ++ 17 ดังนั้นคำตอบที่ถูกต้องคือ "ไม่มีวัตถุประสงค์อย่าใช้"


2
ptrdiff_t            request = 12
pair<int*,ptrdiff_t> p       = get_temporary_buffer<int>(request);
int*                 base    = p.first;
ptrdiff_t            respond = p.sencond;
assert( is_valid( base, base + respond ) );

ตอบสนองอาจจะน้อยกว่าการร้องขอ

size_t require = 12;
int*   base    = static_cast<int*>( ::operator new( require*sizeof(int) ) );
assert( is_valid( base, base + require ) );

ขนาดที่แท้จริงของฐานมากขึ้นต้องหรือเท่ากับต้อง


2

บางที (เป็นเพียงการคาดเดา) มันอาจเกี่ยวข้องกับการกระจายตัวของหน่วยความจำ หากคุณจัดสรรและยกเลิกการจัดสรรหน่วยความจำชั่วคราวอย่างต่อเนื่อง แต่ทุกครั้งที่ทำคุณจะจัดสรรหน่วยความจำระยะยาวที่ต้องการหลังจากจัดสรร temp แต่ก่อนที่จะยกเลิกการจัดสรรคุณอาจจบลงด้วยฮีปที่กระจัดกระจาย (ฉันเดา)

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


1
ความคิดที่น่าสนใจมาก แม้ว่าในปัจจุบันดูเหมือนว่าจะถูกนำไปใช้เป็นสิ่งที่ช่วยให้ทำได้โดยการใช้งานส่วนใหญ่ แต่สิ่งนี้อาจได้รับการสนับสนุนและรวมเข้ากับกิจวัตรการจัดการหน่วยความจำที่เหลืออย่างแน่นหนามากขึ้น ฉันลงคะแนนให้เราโดยคาดหวังว่าสิ่งนี้จะเหมาะกับมันและความคิดเห็นของ Bjarnes ก็ดูเหมือนจะบอกใบ้เช่นกัน
gustaf r

ตอนนี้ฉันได้ดูสิ่งที่ Bjarne พูดเกี่ยวกับเรื่องนี้และเขาบอกว่าออกแบบมาเพื่อการจัดสรรที่รวดเร็วโดยไม่ต้องเริ่มต้น ดังนั้นจึงเป็นเหมือนตัวดำเนินการจัดสรรเท่านั้น (ไม่ใช่ตัวเริ่มต้น) เป็นโมฆะ * ตัวดำเนินการใหม่ (ขนาด size_t) แต่จะจัดสรรได้เร็วกว่าเนื่องจากมีการจัดสรรไว้ล่วงหน้า
Daniel Munoz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.