เหตุใด std :: ssize () จึงถูกนำมาใช้ใน C ++ 20


101

C ++ 20แนะนำstd::ssize()ฟังก์ชันฟรีดังต่อไปนี้:

template <class C>
    constexpr auto ssize(const C& c)
        -> std::common_type_t<std::ptrdiff_t,
                              std::make_signed_t<decltype(c.size())>>;

ดูเหมือนการใช้งานที่เป็นไปได้จะใช้static_castเพื่อแปลงค่าส่งคืนของsize()ฟังก์ชันสมาชิกของ cl ass Cเป็นคู่ที่ลงนาม

เนื่องจากsize()ฟังก์ชันสมาชิกของ C จะส่งกลับค่าที่ไม่ใช่ค่าลบเสมอเหตุใดใคร ๆ จึงต้องการเก็บไว้ในตัวแปรที่ลงชื่อ static_castในกรณีที่ต้องการจริงๆมันเป็นเรื่องของความเรียบง่าย

เหตุใดจึงถูกstd::ssize()นำมาใช้ใน C ++ 20


4
@ Jarod42 ไม่ได้กำหนดการนำไปใช้งานแทนการไม่ได้กำหนดหรือไม่? (การเซ็นชื่อล้นไม่ได้กำหนด แต่การแปลงที่ลงนามได้รับการกำหนดการใช้งาน)
ถึง

9
หากเพียง แต่เพิ่มssizeofตัวดำเนินการด้วย
geza

3
สิ่งนี้อาจเกี่ยวข้องกันบ้าง: stackoverflow.com/questions/30395205/…
Marco13

11
@ JohnZ.Li เสี่ยงต่อการฟังดูไร้เหตุผลเกินไป: ฉันคิดว่าระบบ C ++ ทั้งหมดเกี่ยวกับประเภทจำนวนเต็มเสีย แน่นอนว่าเราสามารถโต้แย้งได้ว่านิสัยใจคอบางอย่าง (เช่นไม่รู้ว่ามีกี่บิตchar) นั้นสืบทอดมาจาก C และอย่างน้อยก็บรรเทาได้บ้าง(u)intX_tแต่ก็ยังคงเป็นแหล่งที่มาของข้อบกพร่องที่ละเอียดอ่อนและสำคัญอย่างไม่สิ้นสุด สิ่งต่างๆเช่นssizeเป็นเพียงแพทช์และจะใช้เวลาสักครู่ (อาจจะ "ตลอดไป") จนกว่าสิ่งนี้จะจมลงใน "แนวทางปฏิบัติที่ดีที่สุด" ทั่วไปที่ผู้คน (สามารถ) ปฏิบัติตามอย่างเข้มงวด
Marco13

6
@ Marco13: ในทางกลับกันระบบประเภท C / C ++ (ซึ่งตรงข้ามกับเช่นระบบประเภทคงที่ของ Java) นอกเหนือจากการอนุญาตให้รหัส C / C ++ ทำงานบนสถาปัตยกรรมที่ภาษาอื่น ๆ ส่วนใหญ่ส่งเสียงดังแล้วยังอนุญาตให้ผู้สอนที่มีความสามารถได้รับความสำคัญ บทเรียนในหัวของนักเรียน เช่นเดียวกับโลกทั้งหมดไม่ใช่ 64 บิต และไม่ไม่ใช่ทุกโลกที่ใช้ตัวอักษร 8 บิต มันเป็นตายง่ายที่จะรับมือกับสิ่งเหล่านี้และมันทำให้คุณเป็นนักพัฒนาที่ดีขึ้นถ้าเพียง แต่อาจารย์จะสอนนี้จากจุดเริ่มต้น (และเพียงเพื่อให้แน่ใจว่าคุณไม่ทราบว่า(u)intX_tประเภทที่มีตัวเลือกที่คุณทำ?)
DevSolar

คำตอบ:


71

มีการอธิบายเหตุผลไว้ในบทความนี้ คำพูด:

เมื่อนำสแปนมาใช้ใน C ++ 17 จะใช้จำนวนเต็มเซ็นชื่อทั้งเป็นดัชนีและขนาด ส่วนหนึ่งก็เพื่ออนุญาตให้ใช้ "-1" เป็นค่า sentinel เพื่อระบุประเภทที่ไม่ทราบขนาดในเวลาคอมไพล์ แต่การมีคอนเทนเนอร์ STL ที่มีฟังก์ชัน size () ส่งคืนค่าที่มีลายเซ็นนั้นเป็นปัญหาดังนั้น P1089 จึงได้รับการแนะนำให้ "แก้ไข" ปัญหา ได้รับการสนับสนุนส่วนใหญ่ แต่ไม่ใช่อัตรากำไร 2 ต่อ 1 ที่จำเป็นสำหรับฉันทามติ

บทความนี้คือ P1227 เป็นข้อเสนอในการเพิ่มฟังก์ชัน std :: ssize ที่ไม่ใช่สมาชิกและสมาชิก ssize () การรวมสิ่งเหล่านี้จะทำให้โค้ดบางอย่างตรงไปตรงมามากขึ้นและช่วยให้สามารถหลีกเลี่ยงการคำนวณขนาดที่ไม่ได้ลงนามที่ไม่ต้องการได้ แนวคิดคือความต้านทานต่อ P1089 จะลดลงหาก ssize () พร้อมใช้งานสำหรับคอนเทนเนอร์ทั้งหมดทั้งผ่าน std :: ssize () และเป็นฟังก์ชันสมาชิก


31
for(int i = 0; i < container.ssize() - 1; ++i)ตัวอย่างยังเป็นธรรมที่น่าสนใจ
Caleth

7
@ จอห์นสำหรับฉันแล้วดูเหมือนว่าพวกเขาสามารถทำสิ่งเดียวกันกับ string :: npos และใช้ size_t (-1) เป็นค่าพิเศษ
rubenvb

15
@ JohnZ.Li ถือว่าผิดพลาดมานานแล้วที่ประเภทขนาด STL ไม่ได้ลงนาม ตอนนี้มันสายเกินไปที่จะปฏิรูป การให้ฟังก์ชันฟรีเป็นสิ่งที่ดีที่สุดที่เราสามารถทำได้ ณ ตอนนี้
LF

16
@LF: มันคือ Herb Sutter ในการประชุม (บางที Bjarne ก็พูดแบบนี้เช่นกัน) แต่เขาผิดนิดหน่อย ตอนนี้ด้วยคอมพิวเตอร์ 32 บิต / 64 บิตขนาดที่เซ็นชื่อจะดีกว่า (เขาพูดถูก) แต่ในสมัยก่อน (ขนาด 16 บิต) ขนาดที่เซ็นชื่อจะไม่ดี (เช่นเราสามารถจัดสรรอาร์เรย์ 32k ไบต์เท่านั้น)
geza

11
@LF: ฉันได้พบสมุนไพรกล่าวขวัญนี้: youtube.com/watch?v=Puio5dly9N8&t=2667 เมื่อเขาบอกว่า "ไม่ได้เกิดขึ้นในทางปฏิบัติ" เป็นความจริงในปัจจุบัน แต่มันไม่เป็นความจริง> 20 ปีที่แล้ว (ระบบ 16 บิต) เลย ดังนั้นจึงไม่ใช่เรื่องผิดมากนักที่จะใช้แบบไม่ได้ลงนามเมื่อ STL ได้รับการออกแบบ
geza

51

จำเป็นที่ถูกขโมยจากเอริค Niebler:

'Unsigned types signal that a negative index/size is not sane'เป็นภูมิปัญญาที่แพร่หลายเมื่อ STL ได้รับการออกแบบครั้งแรก แต่ตามหลักแล้วจำนวนของสิ่งต่างๆไม่จำเป็นต้องเป็นบวก ฉันอาจต้องการนับในจำนวนเต็มที่มีลายเซ็นเพื่อแสดงจำนวนองค์ประกอบที่เพิ่มหรือลบออกจากคอลเลกชัน จากนั้นฉันก็อยากจะรวมกับขนาดของคอลเลกชัน หากขนาดของคอลเลกชันไม่ได้ลงนามตอนนี้ฉันบังคับให้ผสมเลขคณิตที่มีลายเซ็นและเลขคณิตที่ไม่ได้ลงนามซึ่งเป็นฟาร์มบั๊ก คอมไพเลอร์เตือนเกี่ยวกับเรื่องนี้ แต่เนื่องจากการออกแบบของ STL ค่อนข้างบังคับให้โปรแกรมเมอร์เข้าสู่สถานการณ์นี้คำเตือนจึงเป็นเรื่องธรรมดาที่คนส่วนใหญ่ปิดใช้งาน เป็นเรื่องน่าเสียดายเพราะสิ่งนี้ซ่อนข้อบกพร่องที่แท้จริง

การใช้อินเทอร์เฟซที่ไม่ได้ลงนามในอินเทอร์เฟซไม่ใช่ประโยชน์ที่หลายคนคิด หากบังเอิญผู้ใช้ส่งตัวเลขติดลบเล็กน้อยไปยัง API ก็จะกลายเป็นจำนวนบวกมหาศาลทันที หาก API ใช้หมายเลขตามที่ลงชื่อแล้วก็จะสามารถตรวจจับสถานการณ์ได้โดยการยืนยันว่าจำนวนนั้นมากกว่าหรือเท่ากับศูนย์

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


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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.