มันเป็นการดีที่จะกำหนดตัวแปรภายในวงหรือไม่? [ปิด]


15

ผู้สอนของฉันเคยบอกฉันว่าฉันไม่ควรกำหนดตัวแปรภายในลูปแต่ฉันก็ยังคงไม่เข้าใจว่าทำไม

อะไรคือข้อเสียของสิ่งนั้น?

มีร่างกายใดสามารถอธิบายสิ่งนั้นให้ฉันได้บ้าง


7
ผู้สอนของคุณสอนภาษาอะไร
Brian

2
หากคุณกำหนดตัวแปรด้วยชนิดที่ไม่ใช่แบบดั้งเดิมในลูปโปรแกรมของคุณอาจเรียกใช้คอนสตรัคเตอร์ของมันทุกครั้งที่ผ่านลูป หากคุณต้องการกำหนดเพียงครั้งเดียวนอกวงให้ทำเช่นนั้น
Brandin

17
เมื่อคุณมีความสับสนเกี่ยวกับสิ่งที่ผู้สอนพูดทรัพยากรที่ดีที่สุดคือการถามผู้สอน พวกเขาสามารถให้การสื่อสารไปมาอย่างหนาแน่นที่ไซต์ถามและตอบไม่สามารถให้ได้

1
ทำซ้ำข้ามไซต์: ความแตกต่างระหว่างการประกาศตัวแปรก่อนหรือในลูป? (และแน่นอนว่ามีหลายรายการที่ซ้ำกันในเว็บไซต์นั้นสำหรับคำถามเบื้องต้น (รวมถึงคำถามที่มีเฉพาะเกี่ยวกับ C ++))
Peter Mortensen

2
คำแนะนำนั้นเฉพาะเจาะจงกับบริบท เป็นเรื่องของสไตล์ส่วนตัวฉันชอบที่จะประกาศตัวแปรของฉันconstเว้นแต่จะมีเหตุผลที่จะไม่ (นิสัยจากการเขียนโปรแกรมการทำงาน) ฉันจะไม่แก้ไขพวกเขาและเครื่องมือเพิ่มประสิทธิภาพควรตรวจสอบเมื่อพวกเขาไม่ต้องการหรือฉันจะและฉันได้ป้องกันข้อผิดพลาดร้ายแรง เมื่อค่ากลางคงที่เหล่านั้นมีความเฉพาะสำหรับการวนซ้ำของลูปนั่นหมายถึงการประกาศค่าเหล่านั้นภายในลูป อีกครั้งเมื่อคุณต้องการประกาศตัวแปรนอกลูปคือเมื่อคุณจะอ้างถึงตัวแปรภายนอกลูป ตัวอย่างเช่นผลลัพธ์ที่คุณเก็บไว้
Davislor

คำตอบ:


42

ไม่ใช่ปัญหาในการกำหนดตัวแปรภายในลูป ในความเป็นจริงมันเป็นแนวปฏิบัติที่ดีเนื่องจากตัวระบุควรถูก จำกัด ขอบเขตที่เล็กที่สุดเท่าที่จะเป็นไปได้

มีอะไรที่ไม่ดีคือการกำหนดตัวแปรภายในลูปถ้าคุณทำได้เช่นกันก่อนที่ลูปจะรัน ขึ้นอยู่กับความซับซ้อนของด้านขวามือของการมอบหมายสิ่งนี้อาจมีราคาค่อนข้างแพงและอาจควบคุมเวลาการทำงานของลูป หากคุณเขียนลูปที่ใช้ค่าที่คำนวณได้เหมือนกันในการวนซ้ำทั้งหมดคุณควรคำนวณลูปนั้นแน่นอนเหนือลูปซึ่งสำคัญกว่าการย่อขอบเขตให้เล็กที่สุด

เพื่อชี้แจง: ตราบใดที่compute()คืนค่าเดิมเสมอสิ่งนี้

int value = compute();
while (something) {
    doSomething(value);
}

ฉลาดกว่านี้:

while (something) {
    int value = compute();
    doSomething(value);
}

2
คุณจะกำหนดตัวแปรในลูปและกำหนดไว้ก่อนลูปอย่างไร
ชายสวมหน้ากาก

6
@ MaskedMan ฉันคิดว่าคุณเข้าใจผิด ความหมายของ Kilian คือถ้าคุณมีตัวแปรที่กำหนดค่าเดียวกันระหว่างการวนซ้ำของลูปแต่ละครั้งเช่นตั้งค่าตัวแปรวันที่เดียวกันเป็น1/1/1900ตัวแปรควรประกาศและควรกำหนดค่าก่อนลูป
ps2goat

2
ฉันไม่คิดว่ามีคอมไพเลอร์ที่เขียนในช่วงยี่สิบปีที่ผ่านมา (นอกหลักสูตรผู้แปลระดับปริญญาตรี) ที่จะไม่คิดว่าคุณกำหนดค่าเดียวกันในการทำซ้ำแต่ละครั้งและย้ายการมอบหมายนั้นออกจากลูป
TMN

14
@tmn: อย่าให้คอมไพเลอร์ทำในสิ่งที่คุณสามารถทำเองได้ด้วยความชัดเจนของโค้ดที่มากขึ้น
Robert Harvey

10
@TMN ไม่จำเป็นต้อง การปรับให้เหมาะสมนั้นเป็นไปได้ก็ต่อเมื่อคอมไพเลอร์สามารถพิสูจน์ได้ว่าการคำนวณนั้นไม่มีผลข้างเคียง
พอลเดรเปอร์

16

ประเภทที่ซับซ้อนมีตัวสร้างที่ไม่สำคัญและ destructors

สิ่งเหล่านั้นจะถูกเรียกที่จุดเริ่มต้นและจุดสิ้นสุดของลูปเนื้อความ (เนื่องจากเป็นการเริ่มต้นและออกนอกขอบเขต) หากการเตรียมใช้งานมีราคาแพงเช่นนั้นจำเป็นต้องจัดสรรหน่วยความจำบางส่วนแล้วควรหลีกเลี่ยง

อย่างไรก็ตามสำหรับประเภทเล็กน้อยที่ไม่มีปัญหา การจัดสรรและการจัดสรรคืนตัวเองเป็นเพียงการเพิ่มและลบค่าจากตัวชี้สแต็ก (ซึ่งจะได้รับการเพิ่มประสิทธิภาพออก)


ขอบคุณคำตอบที่ฉันกำลังมองหา!
gebbissimo

6

คำแนะนำของเขาง่ายเกินไปเล็กน้อย (นั่นเป็นการพูดน้อย)
ต่อไปนี้มันช่วงตลอดทางจากความคิดที่ดีกว่าที่ใส่ใจและความคิดที่ดีที่จะเป็นไปไม่ได้

  1. คุณควรปฏิบัติตามทุกครั้งที่การใช้ซ้ำนั้นถูกกว่าการทำลายแบบเก่าและการสร้างแบบใหม่

    #include <iostream>
    #include <string>
    
    int main() {
        std::string s; // Don't needlessly free the buffer
        while ((std::cin >> s))
            std::cout << s;
    }
  2. คุณควรหลีกเลี่ยงมันเป็นเรื่องของสไตล์เมื่อมันไม่สำคัญสำหรับการแสดง

    #include <stdio.h>
    #include <stdlib.h>
    int f(int, int);
    
    int main() {
        for (int i = 0; i < 100; ++i) {
            int x = rand(); // Declared here so you don't need to hunt it down.
            printf("%d => %d\n", x, f(x-1, x+i));
        }
    }
  3. คุณจริงๆควรหลีกเลี่ยงมันเมื่อมันมีประสิทธิภาพการทำงานที่เลวร้ายหรือความหมายผิด

    #include <iostream>
    #include <string>
    std::string generate(int);
    
    int main() {
        for(int i = 0; i < 100; ++i) {
            std::string s = generate(i); // Using copy-ellision here
            std::cout << s;
        }
    }
  4. คุณไม่สามารถติดตามได้เมื่อประเภทที่ใช้ไม่อนุญาตให้สลับสับเปลี่ยนหรือย้ายการมอบหมายหรือคัดลอกการมอบหมาย

    #include <iostream>
    #include <puzzle>
    
    int main() {
        for (int i = 0; i < 100; ++i) {
            Puzzle x(i); // Puzzle is an immutable class. For whatever reasons.
            std::cout << x;
        }
    }

2
ขึ้นอยู่กับคำจำกัดความของ "in a loop" ของคุณ 1 สามารถเปลี่ยนเป็น for (std::string s; std::cin >> s;) ...และยังคงเป็น "นอก"
Caleth
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.