วงเล็บปีกกาที่ไม่จำเป็นใน C ++?


187

เมื่อทำการตรวจสอบรหัสสำหรับเพื่อนร่วมงานวันนี้ฉันเห็นสิ่งที่แปลกประหลาด เขาล้อมรอบโค้ดใหม่ด้วยเครื่องหมายปีกกาดังนี้:

Constructor::Constructor()
{
   existing code

   {
      New code: do some new fancy stuff here
   }

   existing code
}

อะไรคือผลลัพธ์ถ้ามีจากนี้? อะไรคือสาเหตุของการทำเช่นนี้? นิสัยนี้มาจากไหน

แก้ไข:

จากข้อมูลที่ป้อนเข้าและคำถามด้านล่างฉันรู้สึกว่าฉันต้องเพิ่มคำถามลงไปแม้ว่าฉันจะทำเครื่องหมายคำตอบแล้ว

สภาพแวดล้อมเป็นอุปกรณ์ฝังตัว มีรหัส C แบบดั้งเดิมจำนวนมากที่ห่อหุ้มด้วยเสื้อผ้า C ++ มีนักพัฒนา C ++ จำนวนมากหันมาใช้ C ++

ไม่มีส่วนที่สำคัญในส่วนนี้ของรหัส ฉันเพิ่งเห็นมันในส่วนนี้ของรหัส ไม่มีการจัดสรรหน่วยความจำที่สำคัญเสร็จสิ้นเพียงตั้งค่าสถานะบางอย่างและตั้งค่าบิต

รหัสที่ล้อมรอบด้วยเครื่องหมายปีกกาคือ:

{
   bool isInit;
   (void)isStillInInitMode(&isInit);
   if (isInit) {
     return isInit;
   }
}

(ไม่ต้องสนใจรหัสแค่ติดเครื่องหมายวงเล็บปีกกา ... ;)) หลังจากเครื่องหมายวงเล็บปีกกามีการเพิ่มเติมเล็กน้อย twiddling ตรวจสอบสถานะและการส่งสัญญาณพื้นฐาน

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

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


99
คำตอบของเพื่อนร่วมงานของคุณคืออะไรเมื่อคุณถามเขาว่าทำไมเขาถึงทำอย่างนั้น?
Graham Borland

20
ค่อนข้างธรรมดากับลวดลาย RAII ภาพรวมอย่างรวดเร็ว: c2.com/cgi/wiki?ResourceAcquisitionIsInitialization
Marcin

9
ฉันเกลียดวงเล็บปีกกาที่ไม่จำเป็น
jacknad

8
มีการประกาศใด ๆ ในบล็อกด้านในหรือไม่
Keith Thompson

15
บางทีเขาอาจจะแค่อยากจะง่าย 'พับห่างออกไปที่ส่วนใหม่ในการแก้ไขของเขา
Wim

คำตอบ:


281

บางครั้งมันก็ดีเพราะมันช่วยให้คุณมีขอบเขตใหม่ซึ่งคุณสามารถ "ประกาศอย่างชัดเจน" ตัวแปรใหม่ (อัตโนมัติ) ได้

ในC++เรื่องนี้อาจไม่สำคัญนักเนื่องจากคุณสามารถแนะนำตัวแปรใหม่ได้ทุกที่ แต่บางทีนิสัยนั้นมาจากCที่ซึ่งคุณไม่สามารถทำสิ่งนี้ได้จนถึง C99 :)

เนื่องจากC++มี destructors มันยังเป็นประโยชน์ในการมีทรัพยากร (ไฟล์, mutexes, อะไรก็ตาม) ที่ปล่อยออกมาโดยอัตโนมัติเมื่อขอบเขตออกมาซึ่งจะทำให้สิ่งต่าง ๆ สะอาดขึ้น ซึ่งหมายความว่าคุณสามารถใช้ทรัพยากรร่วมกันบางอย่างในระยะเวลาที่สั้นกว่าที่คุณต้องการหากคุณคว้ามันในช่วงเริ่มต้นของวิธีการ


37
+1 สำหรับการกล่าวขวัญอย่างชัดเจนของตัวแปรใหม่และนิสัยเก่า
อาร์เน่

46
+1 สำหรับการใช้ขอบเขตบล็อกที่ใช้เพื่อเพิ่มทรัพยากรให้เร็วที่สุด
Leo

9
นอกจากนี้ยังง่ายต่อการ 'ถ้า (0)' บล็อก
vrdhn

ผู้ตรวจสอบโค้ดของฉันมักจะบอกฉันว่าฉันเขียนฟังก์ชั่น / วิธีการที่สั้นเกินไป เพื่อให้พวกเขามีความสุขและเพื่อให้ตัวเองมีความสุข (เช่นการแยกข้อกังวลที่ไม่เกี่ยวข้อง, ตัวแปรท้องถิ่น ฯลฯ ) ฉันใช้เทคนิคนี้ตามที่ @unwind
ossandcad

21
@ossandcad พวกเขาบอกคุณว่าวิธีการของคุณจะ "สั้นเกินไป"? มันยากมากที่จะทำ 90% ของนักพัฒนา (รวมตัวเองน่าจะมี) มีปัญหาตรงข้าม
Ben Lee

169

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


14
แน่นอนว่าบล็อกนั้นควรทำในฟังก์ชั่นแยกต่างหาก
BlueRaja - Danny Pflughoeft

8
บันทึกประวัติ: นี่เป็นเทคนิคจากภาษาซีต้นซึ่งอนุญาตให้สร้างตัวแปรชั่วคราวในท้องถิ่น
โธมัสแมตทิวส์

12
ฉันต้องพูดว่า - แม้ว่าฉันจะพอใจกับคำตอบของฉัน แต่จริงๆแล้วมันไม่ใช่คำตอบที่ดีที่สุดที่นี่ คำตอบที่ดีกว่าพูดถึง RAII อย่างชัดเจนเนื่องจากเป็นเหตุผลหลักว่าทำไมคุณจึงต้องการให้ destructor ถูกเรียก ณ จุดใดจุดหนึ่ง ดูเหมือนว่ากรณีของ "ปืนที่เร็วที่สุดในฝั่งตะวันตก": ฉันโพสต์เร็วพอที่ฉันได้รับ upvotes เร็วพอที่ฉันได้รับ "โมเมนตัม" เพื่อให้ได้ upvotes เร็วกว่าคำตอบที่ดีกว่า ไม่ใช่ว่าฉันบ่น! :-)
ruakh

7
@ BlueRaja-DannyPflughoeft คุณกำลังขยายความ "วางไว้ในฟังก์ชั่นที่แยกต่างหาก" ไม่ใช่วิธีการแก้ปัญหาของรหัสทั้งหมด รหัสในหนึ่งในบล็อกเหล่านี้อาจถูกจับคู่อย่างแน่นหนากับโค้ดที่อยู่ล้อมรอบสัมผัสกับตัวแปรหลายตัว ใช้ฟังก์ชั่น C ที่ต้องใช้การดำเนินการตัวชี้ ยิ่งไปกว่านั้นไม่ใช่ทุกโค้ดขนาดสั้น (หรือควร) นำมาใช้ใหม่ได้และบางครั้งโค้ดอาจไม่เข้าใจในตัวมันเอง บางครั้งฉันวางบล็อกรอบforข้อความของฉันเพื่อสร้างอายุสั้นint i;ใน C89 แน่นอนคุณไม่ได้บอกว่าทุกคนforควรอยู่ในฟังก์ชั่นที่แยกจากกันหรือไม่?
Anders Sjöqvist

101

เครื่องมือจัดฟันพิเศษใช้เพื่อกำหนดขอบเขตของตัวแปรที่ประกาศไว้ภายในเครื่องมือจัดฟัน มีการดำเนินการเพื่อให้ destructor ถูกเรียกเมื่อตัวแปรไม่อยู่ในขอบเขต ใน destructor คุณอาจปล่อย mutex (หรือทรัพยากรอื่น ๆ ) เพื่อให้ผู้อื่นสามารถรับได้

ในรหัสการผลิตของฉันฉันได้เขียนอะไรแบบนี้:

void f()
{
   //some code - MULTIPLE threads can execute this code at the same time

   {
       scoped_lock lock(mutex); //critical section starts here

       //critical section code
       //EXACTLY ONE thread can execute this code at a time

   } //mutex is automatically released here

  //other code  - MULTIPLE threads can execute this code at the same time
}

อย่างที่คุณเห็นในวิธีนี้คุณสามารถใช้scoped_lock ในฟังก์ชั่นและในเวลาเดียวกันสามารถกำหนดขอบเขตของมันโดยใช้วงเล็บปีกกาพิเศษ สิ่งนี้ทำให้แน่ใจว่าแม้ว่าโค้ดภายนอกวงเล็บปีกกาพิเศษสามารถถูกเรียกใช้โดยหลายเธรดพร้อมกัน แต่โค้ดภายในวงเล็บปีกกาจะถูกดำเนินการโดยหนึ่งเธรดในแต่ละครั้ง


1
ฉันคิดว่ามันสะอาดกว่าที่จะมี: scoped_lock lock (mutex) // รหัสส่วนที่สำคัญแล้ว lock.unlock ()
เสียงดังฉ่า

17
@szielenski: เกิดอะไรขึ้นถ้ารหัสจากส่วนที่สำคัญมีข้อยกเว้น? Mutex จะถูกล็อคตลอดไปหรือรหัสจะไม่สะอาดกว่าที่คุณพูด
Nawaz

4
@Nawaz: วิธีการของ @ szielenski จะไม่ปล่อยให้ mutex ล็อกไว้ในกรณีที่มีข้อยกเว้น นอกจากนี้เขายังใช้สิ่งscoped_lockที่จะถูกทำลายในข้อยกเว้น ฉันมักจะต้องการแนะนำขอบเขตใหม่สำหรับล็อคเช่นกัน แต่ในบางกรณีunlockมีประโยชน์มาก เช่นการประกาศตัวแปรท้องถิ่นใหม่ภายในส่วนที่สำคัญแล้วใช้ในภายหลัง (ฉันรู้ว่าฉันมาสาย แต่เพื่อความสมบูรณ์ ... )
Stephan

51

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

อย่างไรก็ตามมีเหตุผลที่ดีอีกประการสำหรับการทำเช่นนี้

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

  • อันนี้มีจุดประสงค์ทางแนวคิดที่สอดคล้องกัน
  • นี่คือรหัสทั้งหมดที่จำเป็น
  • และนี่คือความคิดเห็นเกี่ยวกับก้อน

เช่น

{  // update the moving average
   i= (i+1) mod ARRAYSIZE;
   sum = sum - A[i];
   A[i] = new_value;
   sum = sum + new_value;
   average = sum / ARRAYSIZE ;  
}

คุณอาจโต้แย้งว่าฉันควรเขียนฟังก์ชั่นเพื่อทำสิ่งนั้นทั้งหมด ถ้าฉันทำได้เพียงครั้งเดียวการเขียนฟังก์ชั่นก็แค่เพิ่มไวยากรณ์และพารามิเตอร์เพิ่มเติม ดูเหมือนว่ามีจุดเล็ก ๆ แค่คิดว่านี่เป็นฟังก์ชั่นไร้พารามิเตอร์ที่ไม่ระบุชื่อ

หากคุณโชคดีบรรณาธิการของคุณจะมีฟังก์ชั่นพับ / เปิดออกที่จะให้คุณซ่อนบล็อก

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


23

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


17

นี้เป็นเช่นเดียวกับif(หรือwhileฯลฯ .. ) บล็อกเพียงโดยไม่ต้อง ifกล่าวอีกนัยหนึ่งคุณแนะนำขอบเขตโดยไม่ต้องแนะนำโครงสร้างการควบคุม

โดยทั่วไป "การกำหนดขอบเขตที่ชัดเจน" นี้มีประโยชน์ในกรณีต่อไปนี้:

  1. เพื่อหลีกเลี่ยงการปะทะกันของชื่อ
  2. usingขอบเขต
  3. เพื่อควบคุมเวลาที่เรียกว่า destructors

ตัวอย่างที่ 1:

{
    auto my_variable = ... ;
    // ...
}

// ...

{
    auto my_variable = ... ;
    // ...
}

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

วิธีนี้ช่วยให้คุณหลีกเลี่ยงการใช้งานmy_variableนอกขอบเขตที่ตั้งใจไว้โดยไม่ได้ตั้งใจ

ตัวอย่างที่ 2:

namespace N1 { class A { }; }
namespace N2 { class A { }; }

void foo() {

    {
        using namespace N1;
        A a; // N1::A.
        // ...
    }

    {
        using namespace N2;
        A a; // N2::A.
        // ...
    }

}

สถานการณ์ที่ใช้งานได้จริงเมื่อสิ่งนี้มีประโยชน์น้อยมากและอาจบ่งบอกว่ารหัสนั้นสุกงอมสำหรับการปรับโครงสร้างใหม่ แต่กลไกที่คุณควรจะต้องใช้อย่างแท้จริง

ตัวอย่างที่ 3:

{
    MyRaiiClass guard1 = ...;

    // ...

    {
        MyRaiiClass guard2 = ...;
        // ...
    } // ~MyRaiiClass for guard2 called.

    // ...

} // ~MyRaiiClass for guard1 called.

สิ่งนี้มีความสำคัญสำหรับRAIIในกรณีที่ความจำเป็นในการเพิ่มทรัพยากรไม่ได้ "ตก" ตามขอบเขตของฟังก์ชันหรือโครงสร้างการควบคุม


15

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


14

คนอื่นครอบคลุมขอบเขตอย่างถูกต้องแล้ว RAII ฯลฯ ความเป็นไปได้ แต่เนื่องจากคุณพูดถึงสภาพแวดล้อมแบบฝังตัวมีเหตุผลที่เป็นไปได้อีกประการหนึ่งคือ:

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

ที่นี่isInitน่าจะอยู่ในกอง:

{
   bool isInit;
   (void)isStillInInitMode(&isInit);
   if (isInit) {
     return isInit;
   }
}

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

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


+1 ประเด็นที่ดีถึงแม้ว่าฉันค่อนข้างแน่ใจว่าคอมไพเลอร์สมัยใหม่ได้รับสิทธินี้โดยปราศจากการแทรกแซง (IIRC - คอมไพเลอร์อย่างน้อยไม่ใช่ฝังตัว - พวกเขาไม่สนใจคำว่า 'สมัคร' ไกลกลับเป็น 99 เพราะพวกเขามักจะทำผลงานได้ดีกว่าที่คุณจะทำได้.)
โฟโต้

11

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

// if (false) or if (0) 
{
   //experimental optimization  
}

การปฏิบัตินี้มีประโยชน์ในบางบริบทเช่นการดีบักอุปกรณ์ฝังตัวหรือรหัสส่วนตัว


10

ฉันเห็นด้วยกับ "ruakh" หากคุณต้องการคำอธิบายที่ดีเกี่ยวกับขอบเขตระดับต่าง ๆ ใน C ลองอ่านโพสต์นี้:

ขอบเขตต่าง ๆ ในการประยุกต์ใช้ C

โดยทั่วไปการใช้ "ขอบเขตของบล็อก" จะมีประโยชน์หากคุณต้องการใช้ตัวแปรชั่วคราวที่คุณไม่ต้องติดตามตลอดอายุการใช้งานของการเรียกใช้ฟังก์ชัน นอกจากนี้บางคนใช้เพื่อให้คุณสามารถใช้ชื่อตัวแปรเดียวกันในหลาย ๆ สถานที่เพื่อความสะดวกแม้ว่าโดยทั่วไปจะไม่เป็นความคิดที่ดี เช่น:

int unusedInt = 1;

int main(void) {
  int k;

  for(k = 0; k<10; k++) {
    int returnValue = myFunction(k);
    printf("returnValue (int) is: %d (k=%d)",returnValue,k);
  }

  for(k = 0; k<100; k++) {
    char returnValue = myCharacterFunction(k);
    printf("returnValue (char) is: %c  (k=%d)",returnValue,k);
  }

  return 0;
}

ในตัวอย่างนี้ฉันได้กำหนด returnValue สองครั้ง แต่เนื่องจากมันอยู่ที่ขอบเขตบล็อกแทนที่จะเป็นขอบเขตฟังก์ชัน (เช่น: ขอบเขตของฟังก์ชันจะเป็นตัวอย่างเช่นการประกาศ returnValue หลังจาก int main (void)) ฉันไม่ รับข้อผิดพลาดของคอมไพเลอร์เนื่องจากแต่ละบล็อกไม่สนใจอินสแตนซ์ชั่วคราวของ returnValue ที่ประกาศ

ฉันไม่สามารถพูดได้ว่านี่เป็นความคิดที่ดีโดยทั่วไป (เช่น: คุณอาจไม่ควรใช้ชื่อตัวแปรซ้ำ ๆ จากบล็อกต่อบล็อก) แต่โดยทั่วไปจะช่วยประหยัดเวลาและช่วยให้คุณไม่ต้องจัดการกับ มูลค่าของ returnValue ในฟังก์ชั่นทั้งหมด

สุดท้ายโปรดทราบขอบเขตของตัวแปรที่ใช้ในตัวอย่างโค้ดของฉัน:

int:  unusedInt:   File and global scope (if this were a static int, it would only be file scope)
int:  k:           Function scope
int:  returnValue: Block scope
char: returnValue: Block scope

คำถามไม่ว่างผู้ชาย ฉันไม่เคยมี 100 ups มีอะไรพิเศษเกี่ยวกับคำถามนี้ ลิงค์ที่ดี C มีค่ามากกว่า C ++
Wolfpack'08

5

เหตุใดจึงต้องใช้เครื่องมือจัดฟันแบบ "ไม่จำเป็น"

  • สำหรับวัตถุประสงค์ "การกำหนดขอบเขต" (ดังที่กล่าวไว้ข้างต้น)
  • การทำให้โค้ดอ่านง่ายขึ้น (คล้ายกับการใช้#pragmaหรือการกำหนด "ส่วน" ที่สามารถมองเห็นได้)
  • เพราะว่าคุณทำได้. เรียบง่ายเหมือนที่

PS ไม่ใช่รหัสที่ไม่ดี มันถูกต้อง 100% ดังนั้นมันค่อนข้างเป็นเรื่องของการลิ้มรส (ผิดปกติ)


5

หลังจากดูรหัสในการแก้ไขฉันสามารถพูดได้ว่าวงเล็บที่ไม่จำเป็นอาจเป็น (ในมุมมอง coders ดั้งเดิม) เพื่อให้ชัดเจน 100% สิ่งที่จะเกิดขึ้นในระหว่าง if / then แม้ว่าจะเป็นเพียงบรรทัดเดียวตอนนี้ก็อาจเป็น บรรทัดเพิ่มเติมในภายหลังและวงเล็บรับประกันว่าคุณจะไม่ทำผิด

{
   bool isInit;
   (void)isStillInInitMode(&isInit);
   if (isInit) {
     return isInit;
   }
   return -1;
}

ถ้าข้างต้นเป็นต้นฉบับและการลบ "พิเศษ" woudl ส่งผลให้:

{
   bool isInit;
   (void)isStillInInitMode(&isInit);
   if (isInit) 
     return isInit;
   return -1;
}

หลังจากนั้นการดัดแปลงในภายหลังอาจมีลักษณะเช่นนี้:

{
   bool isInit;
   (void)isStillInInitMode(&isInit);
   if (isInit) 
     CallSomethingNewHere();
     return isInit;
   return -1;
}

และแน่นอนว่าจะทำให้เกิดปัญหาเนื่องจาก isInit จะถูกส่งคืนโดยไม่คำนึงถึง if / then


4

วัตถุจะถูกทำลายโดยอัตโนมัติเมื่อไม่อยู่ในขอบเขต ...


2

อีกตัวอย่างของการใช้งานคือคลาสที่เกี่ยวข้องกับ UI โดยเฉพาะอย่างยิ่ง Qt

ตัวอย่างเช่นคุณมี UI ที่ซับซ้อนและวิดเจ็ตจำนวนมากแต่ละอันมีระยะห่างของตัวเองเลย์เอาต์และอื่น ๆ แทนที่จะตั้งชื่อพวกเขาspace1, space2, spaceBetween, layout1, ...คุณสามารถช่วยตัวเองจากชื่อที่ไม่ใช่คำอธิบายสำหรับตัวแปรที่มีเพียงสองบรรทัดในสามบรรทัด รหัส.

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

// Start video button 
{ 
   <here the code goes> 
}
// Stop video button
{
   <...>
}
// Status label
{
   <...>
}

ไม่สามารถพูดได้ว่าเป็นวิธีปฏิบัติที่ดีที่สุด แต่เป็นรหัสที่ดีสำหรับรหัสดั้งเดิม

มีปัญหาเหล่านี้เมื่อผู้คนจำนวนมากเพิ่มองค์ประกอบของตัวเองลงใน UI และวิธีการบางอย่างก็กลายเป็นเรื่องใหญ่ แต่ก็ไม่ได้เป็นประโยชน์ในการสร้างวิธีการใช้งานเพียงครั้งเดียว 40 วิธีในชั้นเรียนที่ยุ่งเหยิงไปหมดแล้ว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.