ในความหมายที่เข้มงวดที่สุดนี่ไม่ใช่พฤติกรรมที่ไม่ได้กำหนด แต่เป็นการใช้งานที่กำหนดไว้ ดังนั้นถึงแม้ว่าจะไม่เหมาะสมหากคุณวางแผนที่จะสนับสนุนสถาปัตยกรรมที่ไม่สำคัญคุณก็สามารถทำได้
การเสนอราคามาตรฐานที่ได้รับจาก interjay นั้นเป็นสิ่งที่ดีซึ่งบ่งบอกถึง UB แต่มันเป็นเพียงการตีที่ดีที่สุดเป็นอันดับที่สองในความเห็นของฉันเนื่องจากมันเกี่ยวข้องกับการคำนวณทางคณิตศาสตร์ มีย่อหน้าที่เกี่ยวข้องกับการดำเนินการในคำถามโดยตรง:
[expr.post.incr] / [expr.pre.incr]
ตัวถูกดำเนินการจะเป็น [... ] หรือตัวชี้ไปยังประเภทวัตถุที่กำหนดไว้อย่างสมบูรณ์
โอ้เดี๋ยวก่อนเป็นประเภทวัตถุที่กำหนดอย่างสมบูรณ์หรือไม่ นั่นคือทั้งหมดหรือไม่ ฉันหมายถึงพิมพ์จริงเหรอ? ดังนั้นคุณไม่ต้องการวัตถุเลยหรือ?
ใช้เวลาค่อนข้างน้อยในการอ่านเพื่อค้นหาคำใบ้ว่าบางสิ่งบางอย่างในนั้นอาจไม่ได้กำหนดไว้อย่างดีนัก เพราะจนถึงตอนนี้มันอ่านราวกับว่าคุณได้รับอนุญาตให้ทำอย่างสมบูรณ์แบบไม่มีข้อ จำกัด
[basic.compound] 3
ทำให้คำสั่งเกี่ยวกับชนิดของตัวชี้หนึ่งอาจจะมีแล้วเป็นไม่มีอีกสามผลการดำเนินงานของคุณอย่างชัดเจนจะตกอยู่ภายใต้ 3.4: ชี้ไม่ถูกต้อง
อย่างไรก็ตามไม่ได้บอกว่าคุณไม่ได้รับอนุญาตให้มีตัวชี้ที่ไม่ถูกต้อง ในทางตรงกันข้ามมันแสดงรายการเงื่อนไขทั่วไปที่พบบ่อยมาก (เช่นระยะเวลาสิ้นสุดการจัดเก็บ) ซึ่งพอยน์เตอร์กลายเป็นไม่ถูกต้องเป็นประจำ เห็นได้ชัดว่าเป็นสิ่งที่อนุญาตให้เกิดขึ้น และแน่นอน:
[basic.stc] 4 การเปลี่ยนทิศทาง
ผ่านค่าตัวชี้ที่ไม่ถูกต้องและส่งผ่านค่าตัวชี้ที่ไม่ถูกต้องไปยังฟังก์ชันการจัดสรรคืนมีพฤติกรรมที่ไม่ได้กำหนด การใช้ค่าตัวชี้อื่น ๆ ที่ไม่ถูกต้องอื่น ๆ นั้นมีพฤติกรรมที่กำหนดไว้ในการนำไปใช้งาน
เรากำลังทำ "อื่น ๆ" มีดังนั้นมันไม่ใช่พฤติกรรมที่ไม่ได้กำหนด แต่การดำเนินงานที่กำหนดไว้ดังนั้นโดยทั่วไปที่อนุญาต (ยกเว้นกรณีที่การดำเนินการอย่างชัดเจนกล่าวว่าสิ่งที่แตกต่างกัน)
โชคไม่ดีที่นั่นไม่ใช่จุดจบของเรื่อง แม้ว่าผลลัพธ์สุทธิจะไม่เปลี่ยนแปลงจากที่นี่อีกต่อไป แต่จะทำให้เกิดความสับสนมากขึ้นยิ่งคุณค้นหา "ตัวชี้" นานเท่าใด:
[basic.compound]
ค่าที่ถูกต้องของชนิดตัวชี้วัตถุหมายถึงที่อยู่ของไบต์ในหน่วยความจำหรือตัวชี้โมฆะ หากมีวัตถุประเภท T ตั้งอยู่ในที่อยู่ [ ... ] บอกว่าจะชี้ไปที่วัตถุที่ไม่คำนึงถึงวิธีการที่คุ้มค่าที่ได้รับ
[หมายเหตุ: ตัวอย่างเช่นที่อยู่หนึ่งที่ผ่านมาจุดสิ้นสุดของอาร์เรย์จะถูกพิจารณาให้ชี้ไปที่วัตถุที่ไม่เกี่ยวข้องกับประเภทองค์ประกอบของอาร์เรย์ที่อาจอยู่ที่ที่อยู่นั้น [ ... ]]
อ่านเป็น: ตกลงใครสนใจ! ตราบใดที่ตัวชี้ชี้ไปที่ใดที่หนึ่งในความทรงจำฉันก็ดี
[basic.stc.dynamic.safety] ค่าตัวชี้เป็นตัวชี้ที่ได้มาอย่างปลอดภัย [blah blah]
อ่านเป็น: ตกลงมาอย่างปลอดภัยทุกอย่าง มันไม่ได้อธิบายว่านี่คืออะไรและไม่ได้บอกว่าฉันต้องการมันจริงๆ ปลอดภัยที่ได้มาจากที่ห่า เห็นได้ชัดว่าฉันยังคงมีตัวชี้ที่ไม่ได้มาอย่างปลอดภัยได้ดี ฉันเดาว่าการลงทะเบียนพวกเขาอาจจะไม่ใช่ความคิดที่ดี แต่มันก็อนุญาตได้อย่างสมบูรณ์แบบ ไม่พูดอย่างอื่น
การใช้งานอาจมีความปลอดภัยของตัวชี้แบบผ่อนคลายซึ่งในกรณีนี้ความถูกต้องของค่าตัวชี้ไม่ขึ้นอยู่กับว่าเป็นค่าตัวชี้ที่ได้มาอย่างปลอดภัยหรือไม่
โอ้ดังนั้นมันอาจไม่สำคัญแค่สิ่งที่ฉันคิด แต่เดี๋ยวก่อน ... "อาจไม่"? นั่นหมายความว่ามันอาจจะเป็นอย่างดี ฉันจะรู้ได้อย่างไร
อีกวิธีหนึ่งการดำเนินการอาจมีความปลอดภัยของตัวชี้ที่เข้มงวดซึ่งในกรณีที่ค่าตัวชี้ที่ไม่ใช่ค่าตัวชี้ที่ได้มาอย่างปลอดภัยนั้นเป็นค่าตัวชี้ที่ไม่ถูกต้องเว้นแต่ว่าวัตถุที่สมบูรณ์ที่อ้างถึงนั้นมีระยะเวลาเก็บข้อมูลแบบไดนามิก
รอดังนั้นเป็นไปได้ที่ฉันต้องโทรหาdeclare_reachable()
ตัวชี้ทุกตัวหรือไม่ ฉันจะรู้ได้อย่างไร
ตอนนี้คุณสามารถแปลงเป็นintptr_t
ซึ่งกำหนดไว้อย่างดีโดยให้การแทนจำนวนเต็มของตัวชี้ที่ได้มาอย่างปลอดภัย ซึ่งแน่นอนว่าการเป็นจำนวนเต็มนั้นถูกต้องตามกฎหมายอย่างสมบูรณ์และถูกกำหนดไว้อย่างดีเพื่อเพิ่มขึ้นตามที่คุณต้องการ
และใช่คุณสามารถแปลงintptr_t
ด้านหลังเป็นพอยน์เตอร์ซึ่งกำหนดได้ดี เพียงแค่ไม่ใช่ค่าดั้งเดิมมันไม่รับประกันว่าคุณจะมีตัวชี้ที่ได้มาอย่างปลอดภัย (ชัด) ถึงกระนั้นก็ตามในจดหมายถึงมาตรฐานในขณะที่กำหนดการดำเนินการสิ่งนี้เป็นสิ่งที่ถูกต้องตามกฎหมายที่ต้องทำ 100%:
[expr.reinterpret.cast] 5
ค่าประเภทหนึ่งหรือประเภทการแจงนับสามารถแปลงเป็นตัวชี้อย่างชัดเจน ตัวชี้แปลงเป็นจำนวนเต็มขนาดเพียงพอ [... ] และกลับไปเป็นค่าดั้งเดิมชนิดตัวชี้ [... ] เดียวกัน; การแมประหว่างพอยน์เตอร์กับจำนวนเต็มไม่ได้กำหนดไว้
จับ
พอยน์เตอร์เป็นเพียงจำนวนเต็มธรรมดามีเพียงคุณเท่านั้นที่ใช้เป็นพอยน์เตอร์ โอ้ถ้าเป็นเช่นนั้นจริง!
โชคไม่ดีที่มีสถาปัตยกรรมที่ไม่เป็นความจริงเลยและมีเพียงการสร้างตัวชี้ที่ไม่ถูกต้อง (ไม่ใช่การลงทะเบียนมันเพียงแค่มีมันในการลงทะเบียนตัวชี้) จะทำให้เกิดกับดัก
นั่นคือพื้นฐานของ "การปฏิบัติตามที่กำหนด" นั่นและความจริงที่ว่าการเพิ่มตัวชี้เมื่อใดก็ตามที่คุณต้องการแน่นอนว่าคุณสามารถทำให้เกิดการไหลล้นซึ่งมาตรฐานนั้นไม่ต้องการจัดการ จุดสิ้นสุดของพื้นที่ที่อยู่ของแอปพลิเคชันอาจไม่ตรงกับที่ตั้งของการล้นและคุณไม่ทราบด้วยซ้ำว่ามีสิ่งใด ๆ เช่นการล้นสำหรับตัวชี้ในสถาปัตยกรรมเฉพาะ โดยรวมแล้วมันเป็นสิ่งที่น่าหวาดเสียวไม่เกี่ยวกับประโยชน์ที่จะได้รับ
การจัดการกับเงื่อนไข one-past-object บนอีกด้านหนึ่งเป็นเรื่องง่าย: การนำไปปฏิบัติต้องทำให้แน่ใจว่าไม่มีการจัดสรรวัตถุใด ๆ ดังนั้นไบต์สุดท้ายในพื้นที่ที่อยู่จะถูกครอบครอง นั่นคือคำจำกัดความที่ดีเพราะมันมีประโยชน์และไม่สำคัญสำหรับการรับประกัน