คำตอบขึ้นอยู่กับมุมมองของคุณ:
หากคุณตัดสินตามมาตรฐาน C ++ คุณจะไม่สามารถรับข้อมูลอ้างอิงที่เป็นโมฆะได้เนื่องจากคุณได้รับพฤติกรรมที่ไม่ได้กำหนดไว้ก่อน หลังจากอุบัติการณ์ครั้งแรกของพฤติกรรมที่ไม่ได้กำหนดมาตรฐานจะอนุญาตให้ทุกอย่างเกิดขึ้น ดังนั้นหากคุณเขียนแสดง*(int*)0
ว่าคุณมีพฤติกรรมที่ไม่ได้กำหนดไว้แล้วเช่นเดียวกับที่คุณเป็นอยู่แล้วจากมุมมองมาตรฐานของภาษาโดยอ้างถึงตัวชี้ค่าว่าง ส่วนที่เหลือของโปรแกรมไม่เกี่ยวข้องเมื่อดำเนินการนิพจน์นี้คุณจะออกจากเกม
อย่างไรก็ตามในทางปฏิบัติการอ้างอิง null สามารถสร้างได้อย่างง่ายดายจากตัวชี้ค่าว่างและคุณจะไม่สังเกตเห็นจนกว่าคุณจะพยายามเข้าถึงค่าที่อยู่เบื้องหลังการอ้างอิง null ตัวอย่างของคุณอาจเรียบง่ายเกินไปเนื่องจากคอมไพเลอร์การเพิ่มประสิทธิภาพที่ดีจะเห็นลักษณะการทำงานที่ไม่ได้กำหนดไว้และเพียงแค่เพิ่มประสิทธิภาพทุกอย่างที่ขึ้นอยู่กับมัน (การอ้างอิงว่างจะไม่ถูกสร้างขึ้นด้วยซ้ำมันจะถูกปรับให้เหมาะสมที่สุด)
อย่างไรก็ตามการปรับให้เหมาะสมนั้นขึ้นอยู่กับคอมไพลเลอร์เพื่อพิสูจน์พฤติกรรมที่ไม่ได้กำหนดซึ่งอาจไม่สามารถทำได้ พิจารณาฟังก์ชันง่ายๆนี้ภายในไฟล์converter.cpp
:
int& toReference(int* pointer) {
return *pointer;
}
เมื่อคอมไพลเลอร์เห็นฟังก์ชันนี้จะไม่ทราบว่าตัวชี้เป็นตัวชี้ค่าว่างหรือไม่ ดังนั้นจึงสร้างโค้ดที่เปลี่ยนตัวชี้ใด ๆ ให้เป็นการอ้างอิงที่เกี่ยวข้อง (Btw: นี่คือ noop เนื่องจากพอยน์เตอร์และการอ้างอิงเป็นสัตว์ร้ายตัวเดียวกันในแอสเซมเบลอร์) ตอนนี้ถ้าคุณมีไฟล์อื่นที่user.cpp
มีรหัส
#include "converter.h"
void foo() {
int& nullRef = toReference(nullptr);
cout << nullRef; //crash happens here
}
คอมไพเลอร์ไม่ทราบว่า toReference()
จะยกเลิกการอ้างอิงตัวชี้ที่ส่งผ่านและถือว่าส่งคืนการอ้างอิงที่ถูกต้องซึ่งจะเป็นการอ้างอิงที่เป็นโมฆะในทางปฏิบัติ การโทรสำเร็จ แต่เมื่อคุณพยายามใช้ข้อมูลอ้างอิงโปรแกรมขัดข้อง หวังว่า. มาตรฐานอนุญาตให้มีอะไรเกิดขึ้นรวมถึงการปรากฏตัวของช้างสีชมพู
คุณอาจถามว่าเหตุใดจึงเกี่ยวข้องอย่างไรก็ตามพฤติกรรมที่ไม่ได้กำหนดได้ถูกกระตุ้นภายในtoReference()
แล้ว คำตอบคือการดีบัก: การอ้างอิง Null อาจแพร่กระจายและแพร่กระจายได้เช่นเดียวกับที่พอยน์เตอร์ว่างทำ หากคุณไม่ทราบว่าสามารถมีการอ้างอิงที่เป็นโมฆะได้และเรียนรู้ที่จะหลีกเลี่ยงการสร้างสิ่งเหล่านี้คุณอาจใช้เวลาพอสมควรในการพยายามหาสาเหตุว่าทำไมฟังก์ชันสมาชิกของคุณถึงขัดข้องเมื่อพยายามอ่านint
สมาชิกเก่าธรรมดา(คำตอบ: อินสแตนซ์ ในการเรียกของสมาชิกเป็นการอ้างอิงที่เป็นโมฆะดังนั้นthis
ตัวชี้ที่เป็นโมฆะและสมาชิกของคุณจะถูกคำนวณให้อยู่ในตำแหน่งที่อยู่ 8)
แล้วการตรวจสอบการอ้างอิงว่างล่ะ? คุณให้สาย
if( & nullReference == 0 ) // null reference
ในคำถามของคุณ นั่นจะใช้ไม่ได้: ตามมาตรฐานคุณมีพฤติกรรมที่ไม่ได้กำหนดไว้หากคุณยกเลิกการอ้างอิงตัวชี้ว่างและคุณไม่สามารถสร้างการอ้างอิงที่ว่างเปล่าได้โดยไม่ต้องยกเลิกการอ้างอิงตัวชี้ค่าว่างดังนั้นการอ้างอิงที่เป็นโมฆะจะมีอยู่เฉพาะในขอบเขตของพฤติกรรมที่ไม่ได้กำหนดเท่านั้น เนื่องจากคอมไพเลอร์ของคุณอาจคิดว่าคุณไม่ได้ทริกเกอร์พฤติกรรมที่ไม่ได้กำหนดจึงสามารถสันนิษฐานได้ว่าไม่มีสิ่งที่เรียกว่าการอ้างอิงว่าง (แม้ว่ามันจะปล่อยโค้ดที่สร้างการอ้างอิงว่าง!) ดังนั้นมันจึงเห็นif()
เงื่อนไขสรุปว่ามันไม่สามารถเป็นจริงและทิ้งif()
ข้อความทั้งหมด ด้วยการแนะนำการเพิ่มประสิทธิภาพเวลาลิงก์จึงเป็นไปไม่ได้เลยที่จะตรวจสอบการอ้างอิงว่างในวิธีที่มีประสิทธิภาพ
TL; DR:
การอ้างอิงที่เป็นค่าว่างนั้นค่อนข้างมีความน่ากลัว:
การดำรงอยู่ของพวกเขาดูเหมือนจะเป็นไปไม่ได้ (= ตามมาตรฐาน)
แต่มีอยู่จริง (= ตามรหัสเครื่องที่สร้างขึ้น)
แต่คุณไม่สามารถมองเห็นได้หากมีอยู่จริง (= ความพยายามของคุณจะถูกปรับให้เหมาะสมที่สุด)
แต่มันอาจฆ่าคุณโดยไม่รู้ตัวอยู่ดี (= โปรแกรมของคุณขัดข้องในจุดแปลก ๆ หรือแย่กว่านั้น)
ความหวังเดียวของคุณคือไม่มีอยู่จริง (= เขียนโปรแกรมของคุณเพื่อไม่สร้างมัน)
ฉันหวังว่าจะไม่มาหลอกหลอนคุณ!