AIMBOT 2.0
ในตอนที่ 1 ของ New Game 2 เวลาประมาณ 09:40 น. มีโค้ดที่ Nene เขียนไว้:
นี่คือรูปแบบข้อความที่มีการแปลความคิดเห็น:
// the calculation of damage when attacked void DestructibleActor::ReceiveDamage(float sourceDamage) { // apply debuffs auto resolvedDamage = sourceDamage; for (const auto& debuf:m_debufs) { resolvedDamage = debuf.ApplyToDamage(resolvedDamage); m_currentHealth -= resolvedDamage if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); } } }
หลังจากยิงแล้วอุมิโกะชี้ไปที่ห่วงสำหรับบอกว่าสาเหตุที่รหัสล้มเหลวคือมีลูปที่ไม่มีที่สิ้นสุด
ฉันไม่รู้จริงๆว่า C ++ ฉันไม่แน่ใจว่าสิ่งที่เธอพูดเป็นความจริงหรือไม่
จากสิ่งที่ฉันเห็น for loop เป็นเพียงการวนซ้ำผ่าน debufs ที่นักแสดงมีอยู่ในปัจจุบัน เว้นแต่นักแสดงจะมี debufs จำนวนไม่ จำกัด ฉันไม่คิดว่ามันจะกลายเป็นวงวนที่ไม่มีที่สิ้นสุดได้
แต่ฉันไม่แน่ใจว่าเพราะเหตุผลเดียวที่มีการยิงรหัสคือพวกเขาต้องการใส่ไข่อีสเตอร์ที่นี่ใช่ไหม? เราจะได้แค่ภาพด้านหลังของแล็ปท็อปและได้ยิน Umiko พูดว่า "โอ้คุณมีลูปที่ไม่มีที่สิ้นสุดที่นั่น" ความจริงที่ว่าพวกเขาแสดงรหัสบางอย่างทำให้ฉันคิดว่ารหัสนั้นเป็นไข่อีสเตอร์ในบางประเภท
โค้ดจะสร้างลูปแบบไม่สิ้นสุดจริงหรือ?
8- น่าจะเป็นประโยชน์: สกรีนช็อตเพิ่มเติมของ Umiko ที่บอกว่า "มันเป็น เรียกใช้การดำเนินการเดียวกัน ซ้ำแล้วซ้ำเล่า "ซึ่งอาจไม่ปรากฏในโค้ด
- โอ้! ฉันไม่รู้! @AkiTanaka ส่วนย่อยที่ฉันดูบอกว่า "infinite loop"
- @LoganM ฉันไม่ค่อยเห็นด้วย ไม่ใช่แค่ว่า OP มีคำถามเกี่ยวกับซอร์สโค้ดบางอย่างที่มาจากอนิเมะ คำถามของ OP นั้นเกี่ยวกับคำสั่งเฉพาะที่ทำ เกี่ยวกับ ซอร์สโค้ดโดยตัวละครในอะนิเมะและมีคำตอบที่เกี่ยวข้องกับอนิเมะคือ "Crunchyroll ทำผิดและแปลผิดบรรทัด"
- @senshin ฉันคิดว่าคุณกำลังอ่านสิ่งที่คุณต้องการให้เกิดคำถามมากกว่าที่จะถามจริงๆ คำถามจะให้ซอร์สโค้ดบางส่วนและถามว่ามันสร้างลูปแบบไม่สิ้นสุดเป็นโค้ด C ++ ในชีวิตจริงหรือไม่ เกมส์ใหม่! เป็นงานสมมติ ไม่จำเป็นต้องมีรหัสที่นำเสนอเพื่อให้สอดคล้องกับมาตรฐานในชีวิตจริง สิ่งที่ Umiko พูดเกี่ยวกับโค้ดนั้นเชื่อถือได้มากกว่ามาตรฐาน C ++ หรือคอมไพเลอร์ใด ๆ คำตอบด้านบน (ยอมรับ) ไม่มีการกล่าวถึงข้อมูลใด ๆ ในจักรวาล ฉันคิดว่าคำถามตามหัวข้ออาจถูกถามเกี่ยวกับเรื่องนี้ด้วยคำตอบที่ดี แต่ตามที่วลีนี้ไม่ได้เป็นเช่นนั้น
โค้ดไม่ใช่การวนซ้ำแบบไม่มีที่สิ้นสุด แต่เป็นบั๊ก
มีปัญหาสอง (อาจเป็นสาม):
- หากไม่มีการดีบัฟจะไม่มีผลเสียหายใด ๆ
- ความเสียหายที่มากเกินไปจะเกิดขึ้นหากมีมากกว่า 1 ดีบัฟ
- หาก DestroyMe () ลบอ็อบเจ็กต์ทันทีและยังมี m_debuf ที่ต้องประมวลผลลูปจะทำงานบนอ็อบเจ็กต์ที่ถูกลบและทิ้งหน่วยความจำ เอ็นจิ้นเกมส่วนใหญ่มีคิวการทำลายเพื่อแก้ไขปัญหานี้และอื่น ๆ ซึ่งอาจไม่ใช่ปัญหา
การประยุกต์ใช้ความเสียหายควรอยู่นอกวง
นี่คือฟังก์ชันที่ได้รับการแก้ไข:
// the calculation of damage when attacked void DestructibleActor::ReceiveDamage(float sourceDamage) { // apply debuffs auto resolvedDamage = sourceDamage; for (const auto& debuf:m_debufs) { resolvedDamage = debuf.ApplyToDamage(resolvedDamage); } m_currentHealth -= resolvedDamage if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); } }
12 - 15 เราอยู่ใน Code Review หรือไม่? : ง
- การลอยตัว 4 ครั้งนั้นดีต่อสุขภาพหากคุณไม่สูงกว่า 16777216 HP คุณสามารถตั้งค่าสุขภาพเป็นอนันต์เพื่อสร้างศัตรูที่คุณสามารถโจมตีได้ แต่จะไม่ตายและมีการโจมตีครั้งเดียวโดยใช้ความเสียหายที่ไม่สิ้นสุดซึ่งยังคงไม่ฆ่าตัวละคร HP ที่ไม่มีที่สิ้นสุด (ผลลัพธ์ของ INF-INF คือ NaN) แต่ จะฆ่าอย่างอื่น ดังนั้นจึงมีประโยชน์มาก
- 1 @cat โดยการประชุมในหลายมาตรฐานการเข้ารหัส
m_
คำนำหน้าหมายถึงตัวแปรสมาชิก ในกรณีนี้ตัวแปรสมาชิกของDestructibleActor
. - 2 @HotelCalifornia ฉันยอมรับว่ามีโอกาสเล็กน้อย
ApplyToDamage
ไม่ได้ผลตามที่คาดไว้ แต่ในกรณีตัวอย่างที่คุณให้ฉันจะบอกว่าApplyToDamage
ด้วย จำเป็นต้องทำใหม่เพื่อให้ส่งผ่านต้นฉบับsourceDamage
เพื่อให้สามารถคำนวณ debuf ได้อย่างถูกต้องในกรณีเหล่านั้น ในการเป็นคนอวดรู้อย่างแท้จริง: ณ จุดนี้ข้อมูล dmg ควรเป็นโครงสร้างที่มี dmg ดั้งเดิม dmg ปัจจุบันและลักษณะของความเสียหายด้วยเช่นกันหาก debufs มีสิ่งต่างๆเช่น "ความเสี่ยงที่จะยิง" จากประสบการณ์ไม่นานก่อนที่การออกแบบเกมใด ๆ ที่มี debuf จะต้องการสิ่งเหล่านี้ - 1 @StephaneHockenhull พูดได้ดี!
รหัสดูเหมือนจะไม่สร้างลูปที่ไม่มีที่สิ้นสุด
วิธีเดียวที่ลูปจะไม่มีที่สิ้นสุดก็คือถ้า
debuf.ApplyToDamage(resolvedDamage);
หรือ
DestroyMe();
ได้เพิ่มรายการใหม่ลงในไฟล์ m_debufs
ภาชนะ
ดูเหมือนจะไม่น่าเป็นไปได้ และหากเป็นเช่นนั้นโปรแกรมอาจหยุดทำงานได้เนื่องจากการเปลี่ยนคอนเทนเนอร์ในขณะที่ทำซ้ำ
โปรแกรมมักจะขัดข้องเนื่องจากมีการเรียกไปที่ DestroyMe();
ซึ่งน่าจะทำลายวัตถุปัจจุบันที่กำลังรันลูปอยู่
เราอาจคิดว่ามันเป็นการ์ตูนที่ 'คนเลว' เลื่อยกิ่งไม้เพื่อให้ 'คนดี' ตกอยู่กับมัน แต่ก็รู้ตัวว่าสายเกินไปที่เขาอยู่ผิดด้านของการตัด หรือ Midgaard Snake กินหางของมันเอง
ฉันควรเพิ่มด้วยว่าอาการที่พบบ่อยที่สุดของการวนซ้ำแบบไม่มีที่สิ้นสุดคือการหยุดโปรแกรมหรือทำให้ไม่ตอบสนอง โปรแกรมจะหยุดทำงานหากจัดสรรหน่วยความจำซ้ำ ๆ หรือทำบางอย่างที่หารด้วยศูนย์หรือชอบ
จากความคิดเห็นของ Aki Tanaka
อาจเป็นประโยชน์: ภาพหน้าจอเพิ่มเติมของ Umiko ที่บอกว่า "กำลังเรียกใช้การดำเนินการเดียวกันซ้ำแล้วซ้ำเล่า" ซึ่งอาจไม่ปรากฏในรหัส
"มันกำลังเรียกใช้ปฏิบัติการแบบเดิมซ้ำแล้วซ้ำเล่า" นี้มีโอกาสมากขึ้น
สมมติว่า DestroyMe();
ไม่ได้ออกแบบมาให้เรียกมากกว่าหนึ่งครั้งมีแนวโน้มที่จะทำให้เกิดความผิดพลาด
วิธีแก้ไขปัญหานี้คือการเปลี่ยนไฟล์ if
สำหรับสิ่งนี้:
if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); break; }
สิ่งนี้จะออกจากลูปเมื่อ DestructibleActor ถูกทำลายตรวจสอบให้แน่ใจว่า 1) DestroyMe
เรียกเมธอดเพียงครั้งเดียวและ 2) อย่าใช้บัฟอย่างไร้ประโยชน์เมื่อวัตถุนั้นถูกพิจารณาว่าตายแล้ว
- 1 การออกจากลูปเมื่อสุขภาพ <= 0 เป็นการแก้ไขที่ดีกว่าการรอจนกว่าลูปเพื่อตรวจสุขภาพ
- ฉันคิดว่าฉันอาจจะ
break
ออกจากวงและ แล้ว โทรDestroyMe()
เพื่อความปลอดภัย
มีปัญหาหลายประการเกี่ยวกับรหัส:
- หากไม่มีการดีบัฟจะไม่เกิดความเสียหายใด ๆ
DestroyMe()
ชื่อฟังก์ชันฟังดูอันตราย อาจเป็นปัญหาหรือไม่ขึ้นอยู่กับวิธีการใช้งาน หากเป็นเพียงการเรียกใช้ตัวทำลายของวัตถุปัจจุบันที่รวมอยู่ในฟังก์ชันแสดงว่ามีปัญหาเนื่องจากวัตถุจะถูกทำลายตรงกลางของรหัสเรียกใช้งาน หากเป็นการเรียกใช้ฟังก์ชันที่จัดคิวเหตุการณ์การลบของอ็อบเจ็กต์ปัจจุบันก็ไม่มีปัญหาเนื่องจากอ็อบเจ็กต์จะถูกทำลายหลังจากเสร็จสิ้นการเรียกใช้งานและลูปเหตุการณ์เริ่มเข้ามา- ปัญหาจริงที่ดูเหมือนจะกล่าวถึงในอนิเมะเรื่อง "มันกำลังเรียกใช้การดำเนินการแบบเดิมซ้ำแล้วซ้ำเล่า" - มันจะเรียก
DestroyMe()
ตราบเท่าทีm_currentHealth <= 0.f
และยังมีดีบัฟอีกมากที่ต้องทำซ้ำซึ่งอาจส่งผลให้DestroyMe()
ถูกเรียกหลายครั้งซ้ำแล้วซ้ำเล่า ลูปควรหยุดหลังจากครั้งแรกDestroyMe()
โทรเนื่องจากการลบวัตถุมากกว่าหนึ่งครั้งทำให้หน่วยความจำเสียหายซึ่งอาจส่งผลให้เกิดความผิดพลาดในระยะยาว
ฉันไม่แน่ใจจริงๆว่าทำไมการดีบัฟทุกครั้งจึงกำจัดพลังชีวิตแทนที่จะเป็นพลังชีวิตที่ถูกนำไปเพียงครั้งเดียวโดยผลของดีบัฟทั้งหมดจะถูกนำไปใช้กับความเสียหายเริ่มต้น แต่ฉันจะถือว่านั่นเป็นตรรกะของเกมที่ถูกต้อง
รหัสที่ถูกต้องจะเป็น
// the calculation of damage when attacked void DestructibleActor::ReceiveDamage(float sourceDamage) { // apply debuffs auto resolvedDamage = sourceDamage; for (const auto& debuf:m_debufs) { resolvedDamage = debuf.ApplyToDamage(resolvedDamage); m_currentHealth -= resolvedDamage if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); break; } } }
3 - ฉันควรชี้ให้เห็นว่าตามที่ฉันเคยเขียนตัวจัดสรรหน่วยความจำในอดีตการลบหน่วยความจำเดียวกันไม่จำเป็นต้องเป็นปัญหา นอกจากนี้ยังอาจซ้ำซ้อน ทั้งหมดขึ้นอยู่กับพฤติกรรมของผู้จัดสรร เหมืองจะทำหน้าที่เหมือนรายการที่เชื่อมโยงระดับต่ำดังนั้น "โหนด" สำหรับข้อมูลที่ถูกลบจะได้รับการตั้งค่าให้เป็นอิสระหลาย ๆ ครั้งหรือนำออกใหม่หลายครั้ง จับได้ดีแม้ว่า
- Double-free เป็นข้อบกพร่องและโดยทั่วไปแล้วจะนำไปสู่พฤติกรรมที่ไม่ได้กำหนดและข้อขัดข้อง แม้ว่าคุณจะมีตัวจัดสรรที่กำหนดเองซึ่งไม่อนุญาตให้นำที่อยู่หน่วยความจำเดิมมาใช้ซ้ำ แต่การไม่มีสองครั้งเป็นรหัสที่มีกลิ่นเหม็นเนื่องจากไม่มีเหตุผลและคุณจะถูกตะโกนโดยเครื่องวิเคราะห์โค้ดแบบคงที่
- แน่นอน! ฉันไม่ได้ออกแบบมาเพื่อจุดประสงค์นั้น บางภาษาต้องการตัวจัดสรรเนื่องจากไม่มีคุณสมบัติ ไม่ไม่ไม่. ฉันแค่ระบุว่าไม่รับประกันการชน การจำแนกประเภทการออกแบบบางอย่างไม่ผิดพลาดเสมอไป