นี่คือการปฏิบัติที่ยอดเยี่ยม
ด้วยการสร้างตัวแปรภายในลูปคุณมั่นใจได้ว่าขอบเขตของพวกมันถูก จำกัด ไว้ในลูป ไม่สามารถอ้างอิงหรือเรียกใช้ภายนอกลูป
ทางนี้:
หากชื่อของตัวแปรเป็นบิต "ทั่วไป" (เช่น "ฉัน") มีความเสี่ยงที่จะผสมกับตัวแปรที่มีชื่อเดียวกันอื่นที่ไหนสักแห่งในภายหลังในรหัสของคุณ (นอกจากนี้ยังสามารถลดลงได้โดยใช้-Wshadow
คำแนะนำคำเตือนบน GCC)
คอมไพเลอร์รู้ว่าขอบเขตตัวแปรนั้น จำกัด อยู่ภายในลูปดังนั้นจึงจะออกข้อความแสดงข้อผิดพลาดที่เหมาะสมหากตัวแปรนั้นถูกอ้างถึงโดยไม่ได้ตั้งใจที่อื่น
สุดท้าย แต่ไม่ท้ายสุดการเพิ่มประสิทธิภาพเฉพาะบางอย่างสามารถทำได้อย่างมีประสิทธิภาพมากขึ้นโดยคอมไพเลอร์ (ที่สำคัญที่สุดคือการจัดสรรการลงทะเบียน) เนื่องจากรู้ว่าตัวแปรไม่สามารถใช้นอกลูปได้ ตัวอย่างเช่นไม่จำเป็นต้องเก็บผลลัพธ์ไว้เพื่อนำกลับมาใช้ใหม่ในภายหลัง
ในระยะสั้นคุณมีสิทธิ์ที่จะทำ
อย่างไรก็ตามโปรดทราบว่าตัวแปรไม่ควรเก็บค่าไว้ระหว่างแต่ละลูป ในกรณีเช่นนี้คุณอาจต้องเริ่มต้นใหม่ทุกครั้ง นอกจากนี้คุณยังสามารถสร้างบล็อกที่มีขนาดใหญ่กว่าโดยครอบคลุมลูปซึ่งมีวัตถุประสงค์เพียงอย่างเดียวคือการประกาศตัวแปรที่ต้องเก็บค่าของลูปจากที่หนึ่งไปยังอีกที่หนึ่ง โดยทั่วไปจะมีตัวนับลูป
{
int i, retainValue;
for (i=0; i<N; i++)
{
int tmpValue;
/* tmpValue is uninitialized */
/* retainValue still has its previous value from previous loop */
/* Do some stuff here */
}
/* Here, retainValue is still valid; tmpValue no longer */
}
สำหรับคำถาม # 2: ตัวแปรถูกจัดสรรหนึ่งครั้งเมื่อเรียกใช้ฟังก์ชัน ในความเป็นจริงจากมุมมองการจัดสรรมันเป็น (เกือบ) เหมือนกับการประกาศตัวแปรที่จุดเริ่มต้นของฟังก์ชัน ความแตกต่างเพียงอย่างเดียวคือขอบเขต: ตัวแปรไม่สามารถใช้ภายนอกลูป อาจเป็นไปได้ว่าตัวแปรไม่ได้ถูกจัดสรรเพียงแค่ใช้สล็อตฟรีบางตัวอีกครั้ง (จากตัวแปรอื่นที่สิ้นสุดขอบเขต)
ด้วยขอบเขตที่ จำกัด และแม่นยำยิ่งขึ้น แต่ที่สำคัญกว่านั้นคือทำให้รหัสของคุณปลอดภัยยิ่งขึ้นโดยมีสถานะน้อยลง (เช่นตัวแปร) ที่ต้องกังวลเมื่ออ่านส่วนอื่น ๆ ของรหัส
สิ่งนี้เป็นจริงแม้จะอยู่นอกif(){...}
บล็อก โดยทั่วไปแทนที่จะเป็น:
int result;
(...)
result = f1();
if (result) then { (...) }
(...)
result = f2();
if (result) then { (...) }
มันปลอดภัยกว่าที่จะเขียน:
(...)
{
int const result = f1();
if (result) then { (...) }
}
(...)
{
int const result = f2();
if (result) then { (...) }
}
ความแตกต่างอาจดูเล็กน้อยโดยเฉพาะอย่างยิ่งในตัวอย่างเล็ก ๆ แต่ในฐานรหัสขนาดใหญ่ก็จะช่วยให้: ตอนนี้มีความเสี่ยงในการขนส่งบางไม่มีresult
ค่าจากf1()
การf2()
บล็อก แต่ละresult
ข้อ จำกัด ขอบเขตของตัวเองอย่างเคร่งครัดทำให้บทบาทของมันแม่นยำยิ่งขึ้น จากมุมมองของผู้ตรวจสอบมันยอดเยี่ยมกว่าเนื่องจากเขามีตัวแปรสถานะระยะยาวน้อยกว่าที่ต้องกังวลและติดตาม
แม้คอมไพเลอร์จะช่วยให้ดีขึ้น: สมมติว่าในอนาคตหลังจากที่มีการเปลี่ยนแปลงที่ผิดพลาดของรหัสไม่ได้เริ่มต้นอย่างถูกต้องกับresult
f2()
รุ่นที่สองก็จะปฏิเสธที่จะทำงานโดยระบุข้อผิดพลาดที่ชัดเจนในเวลารวบรวม (ทางดีกว่าเวลาทำงาน) รุ่นแรกจะไม่เห็นอะไรเลยผลลัพธ์ของf1()
การทดสอบเพียงครั้งที่สองจะสับสนกับผลลัพธ์ของf2()
ก็จะได้รับการทดสอบเป็นครั้งที่สองถูกสับสนสำหรับผลมาจากการ
ข้อมูลเสริม
CppCheckเครื่องมือโอเพนซอร์ส (เครื่องมือวิเคราะห์แบบคงที่สำหรับรหัส C / C ++) ให้คำแนะนำที่ดีเกี่ยวกับขอบเขตที่เหมาะสมของตัวแปร
เพื่อตอบสนองต่อความคิดเห็นเกี่ยวกับการจัดสรร: กฎข้างต้นเป็นจริงใน C แต่อาจไม่เหมาะกับคลาส C ++ บางคลาส
สำหรับชนิดและโครงสร้างมาตรฐานขนาดของตัวแปรจะทราบได้ในเวลารวบรวม ไม่มีสิ่งที่เรียกว่า "การก่อสร้าง" ใน C ดังนั้นพื้นที่สำหรับตัวแปรจะถูกจัดสรรลงในสแต็ก (โดยไม่มีการกำหนดค่าเริ่มต้น) เมื่อเรียกใช้ฟังก์ชัน นั่นเป็นเหตุผลว่าทำไมต้นทุน "ศูนย์" เมื่อประกาศตัวแปรภายในลูป
อย่างไรก็ตามสำหรับคลาส C ++ มีคอนสตรัคเตอร์ตัวนี้ที่ฉันรู้น้อยมาก ฉันเดาว่าการจัดสรรอาจจะไม่เป็นปัญหาเนื่องจากคอมไพเลอร์จะฉลาดพอที่จะนำพื้นที่เดิมมาใช้ใหม่ได้ แต่การกำหนดค่าเริ่มต้นน่าจะเกิดขึ้นในการวนซ้ำแต่ละครั้ง