คำตอบคือขึ้นอยู่กับมาตรฐาน C ++ ที่คุณกำลังรวบรวม รหัสทั้งหมดถูกสร้างขึ้นอย่างสมบูรณ์แบบในทุกมาตรฐาน‡ยกเว้นบรรทัดนี้:
char * s = "My String";
ตอนนี้สตริงลิเทอรัลมีประเภทconst char[10]
และเรากำลังพยายามเตรียมใช้งานตัวชี้ที่ไม่ใช่คอนสแตนซ์ สำหรับประเภทอื่น ๆ ทั้งหมดนอกเหนือจากchar
ตระกูลของสตริงลิเทอรัลการเริ่มต้นดังกล่าวผิดกฎหมายเสมอ ตัวอย่างเช่น:
const int arr[] = {1};
int *p = arr; // nope!
อย่างไรก็ตามในก่อน C ++ 11 สำหรับตัวอักษรสตริงมีข้อยกเว้นใน§4.2 / 2:
สตริงลิเทอรัล (2.13.4) ที่ไม่ใช่ลิเทอรัลสตริงแบบกว้างสามารถแปลงเป็นค่า r ประเภท " pointer to char "; [... ]. ไม่ว่าในกรณีใดผลลัพธ์คือตัวชี้ไปยังองค์ประกอบแรกของอาร์เรย์ การแปลงนี้จะได้รับการพิจารณาก็ต่อเมื่อมีประเภทเป้าหมายของตัวชี้ที่เหมาะสมอย่างชัดเจนและไม่ใช่เมื่อมีความจำเป็นทั่วไปในการแปลงจาก lvalue เป็น rvalue [หมายเหตุ:การแปลงนี้จะเลิกใช้ ดูภาคผนวก D. ]
ดังนั้นใน C ++ 03 โค้ดจึงใช้ได้ดี (แม้ว่าจะเลิกใช้งานแล้ว) และมีพฤติกรรมที่ชัดเจนและคาดเดาได้
ใน C ++ 11 บล็อกนั้นไม่มีอยู่ - ไม่มีข้อยกเว้นสำหรับตัวอักษรสตริงที่แปลงเป็นchar*
ดังนั้นรหัสจึงมีรูปแบบที่ไม่ถูกต้องตามint*
ตัวอย่างที่ฉันให้ไว้ คอมไพเลอร์มีหน้าที่ต้องออกการวินิจฉัยและในกรณีเช่นนี้เป็นการละเมิดที่ชัดเจนของระบบประเภท C ++ เราคาดหวังว่าคอมไพเลอร์ที่ดีจะไม่เพียง แต่สอดคล้องในเรื่องนี้ (เช่นโดยการออกคำเตือน) แต่จะล้มเหลว ทันที.
โค้ดไม่ควรคอมไพล์ - แต่ทำทั้งบน gcc และ clang (ฉันคิดว่าเพราะอาจมีโค้ดจำนวนมากที่จะเสียโดยมีกำไรเพียงเล็กน้อยแม้ว่ารูระบบประเภทนี้จะเลิกใช้งานมานานกว่าทศวรรษแล้วก็ตาม) รหัสมีรูปแบบที่ไม่ถูกต้องดังนั้นจึงไม่สมเหตุสมผลที่จะให้เหตุผลเกี่ยวกับลักษณะการทำงานของโค้ด แต่เมื่อพิจารณาถึงกรณีเฉพาะนี้และประวัติที่ได้รับอนุญาตก่อนหน้านี้ฉันไม่เชื่อว่าจะเป็นการยืดที่ไม่มีเหตุผลในการตีความรหัสผลลัพธ์ราวกับว่าเป็นโดยนัยconst_cast
บางอย่างเช่น:
const int arr[] = {1};
int *p = const_cast<int*>(arr); // OK, technically
ด้วยเหตุนี้โปรแกรมที่เหลือจึงสมบูรณ์แบบอย่างที่คุณไม่เคยสัมผัสs
อีกเลย การอ่านconst
วัตถุที่สร้างขึ้นโดยไม่ใช้const
ตัวชี้นั้นทำได้ดีมาก การเขียนconst
วัตถุที่สร้างขึ้นผ่านตัวชี้นั้นเป็นพฤติกรรมที่ไม่ได้กำหนด:
std::cout << *p; // fine, prints 1
*p = 5; // will compile, but undefined behavior, which
// certainly qualifies as "unpredictable"
เนื่องจากไม่มีการแก้ไขผ่านs
ที่ใดก็ได้ในโค้ดของคุณโปรแกรมจึงใช้ได้ใน C ++ 03 ควรล้มเหลวในการคอมไพล์ใน C ++ 11 แต่จะดำเนินการต่อ - และเนื่องจากคอมไพเลอร์อนุญาตจึงยังไม่มีพฤติกรรมที่ไม่ได้กำหนดไว้ในนั้น† . ด้วยค่าเผื่อที่คอมไพลเลอร์ยังคง [ไม่ถูกต้อง] ตีความกฎ C ++ 03 ฉันไม่เห็นสิ่งใดที่จะนำไปสู่พฤติกรรมที่ "คาดเดาไม่ได้" เขียนถึงs
แม้ว่าและการเดิมพันทั้งหมดจะปิดลง ทั้งใน C ++ 03 และ C ++ 11
†แม้ว่าอีกครั้งตามคำนิยามรหัสที่มีรูปแบบไม่ถูกต้องไม่ให้ความคาดหวังถึงพฤติกรรมที่สมเหตุสมผล
‡ยกเว้นไม่ดูคำตอบของ Matt McNabb