ทั้งสองอย่าง(a)
และ(b)
ส่งผลให้เกิดพฤติกรรมที่ไม่ได้กำหนด พฤติกรรมที่ไม่ได้กำหนดไว้เสมอในการเรียกใช้ฟังก์ชันสมาชิกผ่านตัวชี้ค่าว่าง หากฟังก์ชันเป็นแบบคงที่แสดงว่าไม่ได้กำหนดไว้ในทางเทคนิคเช่นกัน แต่มีข้อโต้แย้งบางประการ
สิ่งแรกที่ต้องทำความเข้าใจคือเหตุใดพฤติกรรมที่ไม่ได้กำหนดไว้ในการหักล้างตัวชี้ค่าว่าง ใน C ++ 03 มีความคลุมเครืออยู่เล็กน้อยที่นี่
แม้ว่า"การยกเลิกการอ้างอิงตัวชี้ค่าว่างจะทำให้เกิดพฤติกรรมที่ไม่ได้กำหนด"ในบันทึกย่อทั้ง§1.9 / 4 และ§8.3.2 / 4 แต่ก็ไม่เคยระบุไว้อย่างชัดเจน (หมายเหตุไม่ใช่กฎเกณฑ์)
อย่างไรก็ตามเราสามารถลองอนุมานได้จาก§3.10 / 2:
lvalue หมายถึงวัตถุหรือฟังก์ชัน
เมื่อยกเลิกการอ้างอิงผลลัพธ์จะเป็นค่า lvalue ตัวชี้ค่าว่างไม่ได้อ้างถึงวัตถุดังนั้นเมื่อเราใช้ lvalue เราจึงมีพฤติกรรมที่ไม่ได้กำหนดไว้ ปัญหาคือไม่เคยระบุประโยคก่อนหน้าดังนั้นการ "ใช้" lvalue หมายความว่าอย่างไร? เพียงแค่สร้างมันขึ้นมาเลยหรือจะใช้ในความหมายที่เป็นทางการมากขึ้นของการแปลง lvalue-to-rvalue?
ไม่ว่าจะไม่สามารถแปลงเป็นค่า r ((4.1 / 1) ได้แน่นอน:
หากอ็อบเจ็กต์ที่ lvalue อ้างถึงไม่ใช่อ็อบเจ็กต์ประเภท T และไม่ใช่อ็อบเจ็กต์ประเภทที่มาจาก T หรือถ้าอ็อบเจ็กต์ไม่ได้กำหนดค่าเริ่มต้นโปรแกรมที่จำเป็นต้องมีการแปลงนี้จะมีพฤติกรรมที่ไม่ได้กำหนดไว้
นี่คือพฤติกรรมที่ไม่ได้กำหนดไว้อย่างแน่นอน
ความคลุมเครือมาจากพฤติกรรมที่ไม่ได้กำหนดเป็นการเบี่ยงเบนหรือไม่แต่ไม่ใช้ค่าจากตัวชี้ที่ไม่ถูกต้อง (นั่นคือรับค่า lvalue แต่ไม่แปลงเป็นค่า rvalue) ถ้าไม่เช่นนั้นก็int *i = 0; *i; &(*i);
มีการกำหนดไว้อย่างดี นี่เป็นปัญหาที่เกิดขึ้น
ดังนั้นเราจึงมีมุมมอง "dereference a null pointer ที่ไม่ได้กำหนดพฤติกรรมที่ไม่ได้กำหนด" และจุดอ่อน "ใช้ตัวชี้ค่า null ที่ไม่ได้อ้างอิงได้รับมุมมองพฤติกรรมที่ไม่ได้กำหนด"
ตอนนี้เราพิจารณาคำถาม
ใช่(a)
ส่งผลให้เกิดพฤติกรรมที่ไม่ได้กำหนด ในความเป็นจริงถ้าthis
เป็นโมฆะโดยไม่คำนึงถึงเนื้อหาของฟังก์ชันผลลัพธ์จะไม่ได้กำหนด
สิ่งนี้มาจาก§5.2.5 / 3:
หากE1
มีประเภท "ตัวชี้เป็นคลาส X" นิพจน์E1->E2
จะถูกแปลงเป็นรูปแบบที่เทียบเท่า(*(E1)).E2;
*(E1)
จะส่งผลให้เกิดพฤติกรรมที่ไม่ได้กำหนดด้วยการตีความที่เข้มงวดและ.E2
แปลงเป็นค่า r ทำให้เป็นพฤติกรรมที่ไม่ได้กำหนดไว้สำหรับการตีความที่อ่อนแอ
นอกจากนี้ยังเป็นไปตามพฤติกรรมที่ไม่ได้กำหนดโดยตรงจาก (§9.3.1 / 1):
ถ้าฟังก์ชันสมาชิกที่ไม่คงที่ของคลาส X ถูกเรียกใช้สำหรับอ็อบเจ็กต์ที่ไม่ใช่ประเภท X หรือประเภทที่มาจาก X พฤติกรรมนั้นจะไม่ได้กำหนดไว้
ด้วยฟังก์ชันคงที่การตีความที่เข้มงวดและอ่อนแอทำให้เกิดความแตกต่าง พูดอย่างเคร่งครัดไม่ได้กำหนด:
สมาชิกแบบคงที่อาจถูกอ้างถึงโดยใช้ไวยากรณ์การเข้าถึงของสมาชิกคลาสซึ่งในกรณีนี้จะมีการประเมินนิพจน์อ็อบเจ็กต์
นั่นคือมันเป็นเพียงการประเมินราวกับว่ามันเป็นไม่คงที่และเราอีกครั้ง dereference (*(E1)).E2
ชี้โมฆะด้วย
อย่างไรก็ตามเนื่องจากE1
ไม่ได้ใช้ในการเรียกฟังก์ชันสมาชิกแบบคงที่ถ้าเราใช้การแปลความหมายที่ไม่ชัดเจนการเรียกจะถูกกำหนดไว้อย่างดี *(E1)
ผลลัพธ์ใน lvalue ฟังก์ชันคงที่ได้รับการแก้ไข*(E1)
ถูกละทิ้งและฟังก์ชันนี้ถูกเรียกใช้ ไม่มีการแปลงค่า lvalue-to-rvalue ดังนั้นจึงไม่มีพฤติกรรมที่ไม่ได้กำหนด
ใน C ++ 0x ณ n3126 ความคลุมเครือยังคงอยู่ ตอนนี้ปลอดภัย: ใช้การตีความอย่างเคร่งครัด