เป็นความจริงหรือไม่ที่goto
กระโดดข้ามบิตของรหัสโดยไม่เรียกผู้ทำลายและสิ่งของ?
เช่น
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
จะไม่x
รั่วไหล?
เป็นความจริงหรือไม่ที่goto
กระโดดข้ามบิตของรหัสโดยไม่เรียกผู้ทำลายและสิ่งของ?
เช่น
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
จะไม่x
รั่วไหล?
"Won't x be leaked"
หมายถึง? ประเภทของx
เป็นชนิดข้อมูลในตัว ทำไมคุณไม่เลือกตัวอย่างที่ดีกว่านี้
goto
พวกเขาคิดว่าแม้แต่ตัวแปรระยะเวลาการจัดเก็บอัตโนมัติก็ยัง "รั่วไหล" ที่คุณและฉันรู้ว่าเป็นอย่างอื่นนอกเหนือจากประเด็น
int
ไม่สามารถรั่วไหลได้ แต่ก็สามารถรั่วได้ ตัวอย่างเช่น: การvoid f(void) { new int(5); }
รั่วไหลของint
ไฟล์.
คำตอบ:
คำเตือน:คำตอบนี้เกี่ยวข้องกับ C ++ เท่านั้น ; กฎค่อนข้างแตกต่างกันใน C.
จะไม่
x
รั่วไหล?
ไม่ไม่อย่างแน่นอน
เป็นตำนานที่goto
เป็นโครงสร้างระดับต่ำที่ช่วยให้คุณสามารถแทนที่กลไกการกำหนดขอบเขตในตัวของ C ++ (ถ้ามีอะไรก็longjmp
อาจจะเกิดปัญหานี้ได้)
พิจารณากลไกต่อไปนี้ที่ป้องกันไม่ให้คุณทำ "สิ่งที่ไม่ดี" กับป้ายกำกับ (ซึ่งรวมถึงcase
ป้ายกำกับ)
คุณไม่สามารถข้ามฟังก์ชันต่างๆได้:
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
// error: label 'lol' used but not defined
[n3290: 6.1/1]:
[.. ] ขอบเขตของป้ายชื่อคือฟังก์ชันที่ปรากฏ [.. ]
คุณไม่สามารถข้ามการเริ่มต้นวัตถุ:
int main() {
goto lol;
int x = 0;
lol:
return 0;
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘int x’
หากคุณข้ามกลับไปที่การเริ่มต้นอ็อบเจ็กต์ "อินสแตนซ์" ก่อนหน้าของออบเจ็กต์จะถูกทำลาย :
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
int x = 0;
lol:
T t;
if (x++ < 5)
goto lol;
}
// Output: *T~T*T~T*T~T*T~T*T~T*T~T
[n3290: 6.6/2]:
[.. ] การถ่ายโอนออกจากลูปออกจากบล็อกหรือย้อนกลับผ่านตัวแปรเริ่มต้นที่มีระยะเวลาการจัดเก็บอัตโนมัติเกี่ยวข้องกับการทำลายวัตถุที่มีระยะเวลาการจัดเก็บอัตโนมัติที่อยู่ในขอบเขตที่จุดที่ถ่ายโอนจาก แต่ไม่ได้ถ่ายโอนไปที่จุด . [.. ]
คุณไม่สามารถข้ามไปยังขอบเขตของวัตถุแม้ว่าจะไม่ได้เริ่มต้นอย่างชัดเจน:
int main() {
goto lol;
{
std::string x;
lol:
x = "";
}
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘std::string x’
... ยกเว้นวัตถุบางประเภทซึ่งภาษาสามารถจัดการได้โดยไม่คำนึงถึงเพราะไม่ต้องการโครงสร้างที่ "ซับซ้อน":
int main() {
goto lol;
{
int x;
lol:
x = 0;
}
}
// OK
[n3290: 6.7/3]:
เป็นไปได้ที่จะถ่ายโอนไปยังบล็อก แต่ไม่ใช่ในลักษณะที่ข้ามการประกาศด้วยการเริ่มต้น โปรแกรมที่กระโดดจากจุดที่ตัวแปรที่มีระยะเวลาการจัดเก็บอัตโนมัติไม่อยู่ในขอบเขตไปยังจุดที่อยู่ในขอบเขตนั้นมีรูปแบบที่ไม่ถูกต้องเว้นแต่ตัวแปรจะมีประเภทสเกลาร์ประเภทคลาสที่มีตัวสร้างเริ่มต้นเล็กน้อยและตัวทำลายเล็กน้อย a เวอร์ชันที่ผ่านการรับรอง cv ของประเภทใดประเภทหนึ่งเหล่านี้หรืออาร์เรย์ของประเภทก่อนหน้าและประกาศโดยไม่มีตัวเริ่มต้น [.. ]
ในทำนองเดียวกันวัตถุที่มีระยะเวลาการจัดเก็บอัตโนมัติจะไม่ "รั่วไหล" เมื่อคุณอยู่goto
นอกขอบเขต :
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
{
T t;
goto lol;
}
lol:
return 0;
}
// *T~T
[n3290: 6.6/2]:
เมื่อออกจากขอบเขต (แต่ทำได้สำเร็จ) อ็อบเจ็กต์ที่มีระยะเวลาการจัดเก็บอัตโนมัติ (3.7.3) ที่สร้างขึ้นในขอบเขตนั้นจะถูกทำลายตามลำดับย้อนกลับของการสร้าง [.. ]
กลไกข้างต้นช่วยให้มั่นใจได้ว่าคุณgoto
จะไม่ทำลายภาษา
ของหลักสูตรนี้ไม่ได้หมายความว่าคุณ "ควรจะ" ใช้goto
สำหรับปัญหาใดก็ตาม แต่ก็ไม่หมายความว่ามันไม่ได้เกือบเป็น "ความชั่ว" เป็นตำนานคนทั่วไปนำไปสู่ความเชื่อ