Anonim

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) อย่าใช้บัฟอย่างไร้ประโยชน์เมื่อวัตถุนั้นถูกพิจารณาว่าตายแล้ว

2
  • 1 การออกจากลูปเมื่อสุขภาพ <= 0 เป็นการแก้ไขที่ดีกว่าการรอจนกว่าลูปเพื่อตรวจสุขภาพ
  • ฉันคิดว่าฉันอาจจะ break ออกจากวงและ แล้ว โทร DestroyMe()เพื่อความปลอดภัย

มีปัญหาหลายประการเกี่ยวกับรหัส:

  1. หากไม่มีการดีบัฟจะไม่เกิดความเสียหายใด ๆ
  2. DestroyMe() ชื่อฟังก์ชันฟังดูอันตราย อาจเป็นปัญหาหรือไม่ขึ้นอยู่กับวิธีการใช้งาน หากเป็นเพียงการเรียกใช้ตัวทำลายของวัตถุปัจจุบันที่รวมอยู่ในฟังก์ชันแสดงว่ามีปัญหาเนื่องจากวัตถุจะถูกทำลายตรงกลางของรหัสเรียกใช้งาน หากเป็นการเรียกใช้ฟังก์ชันที่จัดคิวเหตุการณ์การลบของอ็อบเจ็กต์ปัจจุบันก็ไม่มีปัญหาเนื่องจากอ็อบเจ็กต์จะถูกทำลายหลังจากเสร็จสิ้นการเรียกใช้งานและลูปเหตุการณ์เริ่มเข้ามา
  3. ปัญหาจริงที่ดูเหมือนจะกล่าวถึงในอนิเมะเรื่อง "มันกำลังเรียกใช้การดำเนินการแบบเดิมซ้ำแล้วซ้ำเล่า" - มันจะเรียก 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 เป็นข้อบกพร่องและโดยทั่วไปแล้วจะนำไปสู่พฤติกรรมที่ไม่ได้กำหนดและข้อขัดข้อง แม้ว่าคุณจะมีตัวจัดสรรที่กำหนดเองซึ่งไม่อนุญาตให้นำที่อยู่หน่วยความจำเดิมมาใช้ซ้ำ แต่การไม่มีสองครั้งเป็นรหัสที่มีกลิ่นเหม็นเนื่องจากไม่มีเหตุผลและคุณจะถูกตะโกนโดยเครื่องวิเคราะห์โค้ดแบบคงที่
  • แน่นอน! ฉันไม่ได้ออกแบบมาเพื่อจุดประสงค์นั้น บางภาษาต้องการตัวจัดสรรเนื่องจากไม่มีคุณสมบัติ ไม่ไม่ไม่. ฉันแค่ระบุว่าไม่รับประกันการชน การจำแนกประเภทการออกแบบบางอย่างไม่ผิดพลาดเสมอไป