เมื่อใดฉันจึงควรเขียนคำหลัก 'อินไลน์' สำหรับฟังก์ชั่น / วิธีการ?


562

ฉันควรเขียนคำหลักเมื่อใด inlineสำหรับฟังก์ชั่น / วิธีการใน C ++ เมื่อใด

หลังจากเห็นคำตอบบางคำถามที่เกี่ยวข้อง:

  • เมื่อใดที่ฉันไม่ควรเขียนคำว่า 'อินไลน์' สำหรับฟังก์ชั่น / วิธีการใน C ++

  • เมื่อไรที่คอมไพเลอร์ไม่ทราบว่าจะสร้างฟังก์ชั่น / เมธอด 'inline' เมื่อใด

  • มันมีความสำคัญอย่างไรหากแอปพลิเคชันนั้นมีหลายเธรดเมื่อมีการเขียน 'inline' สำหรับฟังก์ชั่น / วิธีการ?


40
หากคุณกำหนดฟังก์ชั่นในส่วนหัวคุณจะต้องประกาศแบบอินไลน์ มิฉะนั้นคุณจะได้รับข้อผิดพลาด linker เกี่ยวกับคำจำกัดความหลายฟังก์ชั่น
Martin York

15
@ มาร์ติน: ยกเว้นว่ามันจะอยู่ในคำจำกัดความของชั้นเรียนที่จะจู้จี้จุกจิก
David Thornley

20
@David: เพื่อจู้จี้จุกจิกพิเศษนั่นเป็นเพราะฟังก์ชั่นดังกล่าวมีการทำเครื่องหมายโดยนัยinline(9.3 / 2)
Lightness Races ในวงโคจร


ดูฟังก์ชันแบบอินไลน์ในคำถามที่พบบ่อย C ++ พวกเขามีการรักษาแบบอินไลน์ที่ดีมาก
jww

คำตอบ:


882

โอ้มนุษย์หนึ่งในสัตว์เลี้ยงของฉันโกรธ

inlineเหมือนstaticหรือexternมากกว่าคำสั่งที่บอกให้คอมไพเลอร์อินไลน์ฟังก์ชั่นของคุณ extern, static, inlineมีแนวทางการเชื่อมโยงที่ใช้เกือบโดยเฉพาะลิงเกอร์ที่ไม่ได้คอมไพเลอร์

มันบอกว่าinlineคำแนะนำของคอมไพเลอร์ที่คุณคิดว่าฟังก์ชั่นควรจะถูกแทรก ที่อาจเป็นจริงในปี 1998 แต่ทศวรรษต่อมาคอมไพเลอร์ไม่ต้องการคำแนะนำดังกล่าว ไม่พูดถึงมนุษย์มักจะผิดเมื่อมันมาถึงการปรับรหัสให้เหมาะสมดังนั้นคอมไพเลอร์ส่วนใหญ่จึงไม่สนใจ 'hint'

  • static- ชื่อตัวแปร / ฟังก์ชั่นไม่สามารถใช้ในหน่วยการแปลอื่น ๆ Linker ต้องตรวจสอบให้แน่ใจว่าไม่ได้ใช้ตัวแปร / ฟังก์ชั่นที่กำหนดไว้แบบคงที่จากหน่วยการแปลอื่นโดยไม่ตั้งใจ

  • extern- ใช้ชื่อตัวแปร / ฟังก์ชั่นนี้ในหน่วยการแปลนี้ แต่อย่าบ่นหากไม่ได้กำหนดไว้ ตัวเชื่อมโยงจะเรียงลำดับและตรวจสอบให้แน่ใจว่ารหัสทั้งหมดที่พยายามใช้สัญลักษณ์ extern มีที่อยู่

  • inline- ฟังก์ชั่นนี้จะถูกกำหนดไว้ในหลาย ๆ หน่วยการแปลไม่ต้องกังวลกับมัน ตัวเชื่อมโยงต้องตรวจสอบให้แน่ใจว่าหน่วยการแปลทั้งหมดใช้อินสแตนซ์เดียวของตัวแปร / ฟังก์ชัน

หมายเหตุ:โดยทั่วไปการประกาศเทมเพลตinlineนั้นไม่มีประโยชน์เนื่องจากมีความหมายเชื่อมโยงกันinlineอยู่แล้ว อย่างไรก็ตามความเชี่ยวชาญที่ชัดเจนและ instantiation ของแม่จำเป็นต้องinlineที่จะใช้


คำตอบเฉพาะสำหรับคำถามของคุณ:

  • เมื่อใดฉันจึงควรเขียนคำหลัก 'อินไลน์' สำหรับฟังก์ชั่น / วิธีการใน C ++?

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

  • เมื่อใดที่ฉันไม่ควรเขียนคำว่า 'อินไลน์' สำหรับฟังก์ชั่น / วิธีการใน C ++

    อย่าเพิ่มอินไลน์เพียงเพราะคุณคิดว่าโค้ดของคุณจะทำงานเร็วขึ้นหากคอมไพเลอร์อินไลน์

  • เมื่อไรที่คอมไพเลอร์ไม่ทราบว่าจะสร้างฟังก์ชั่น / เมธอด 'inline' เมื่อใด

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

    เช่นกันเพื่อป้องกันไม่ให้อินไลน์ใน GCC ใช้__attribute__(( noinline ))และใน Visual Studio, __declspec(noinline)การใช้งาน

  • มันมีความสำคัญอย่างไรหากแอปพลิเคชันนั้นมีหลายเธรดเมื่อมีการเขียน 'inline' สำหรับฟังก์ชั่น / วิธีการ?

    มัลติเธรดไม่ส่งผลกระทบต่อการอินไลน์ในทางใด ๆ


172
+1 คำอธิบายอินไลน์ที่ดีที่สุดที่ฉันเคยเห็น ... (ตลอดกาล) ตอนนี้ฉันจะฉ้อคุณและใช้สิ่งนี้ในคำอธิบายทั้งหมดของคำหลักแบบอินไลน์
Martin York

6
@ Ziggy สิ่งที่ฉันพยายามจะพูดคือคอมไพเลอร์อินไลน์และinlineคำหลักนั้นไม่เกี่ยวข้องกัน คุณมีความคิดที่ถูกต้องแล้ว ตามกฎแล้วการคาดเดาสิ่งที่จะได้รับการปรับปรุงโดยการอินไลน์เป็นข้อผิดพลาดอย่างมาก ข้อยกเว้นสำหรับกฎนั้นคือหนึ่ง liners
deft_code

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

5
คอมไพเลอร์จะเรียกฟังก์ชั่นอินไลน์เฉพาะเมื่อมีการกำหนดที่ไซต์การโทร การออกจากฟังก์ชั่นทั้งหมดในไฟล์ cpp จะเป็นการ จำกัด การอินไลน์กับไฟล์นั้น ฉันขอแนะนำให้กำหนดขนาดเล็กหนึ่ง liners แบบอินไลน์ใน. h เป็นค่าใช้จ่ายในการรวบรวมความเร็วเป็นเล็กน้อยและคุณเกือบรับประกันว่าคอมไพเลอร์จะอินไลน์โทร จุดของฉันเกี่ยวกับการคอมไพเลอร์อินไลน์คือว่ามันเป็นพอร์ตของศิลปะการเพิ่มประสิทธิภาพสีดำซึ่งคอมไพเลอร์ของคุณดีกว่าคุณมาก
deft_code

8
เมื่อใดก็ตามที่ฉันอ่านบางสิ่งบางอย่างในบัญชีของความรู้สะสมของอินเทอร์เน็ตฉันต้องคิดถึงคำพูดที่โด่งดังของ John Lawton: การประชดของยุคข้อมูลข่าวสารคือการให้ความเคารพใหม่กับความคิดเห็นที่ไม่รู้ตัว
IInspectable

60

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

รับไฟล์ต้นฉบับสองไฟล์เช่น:

  • inline111.cpp:

    #include <iostream>
    
    void bar();
    
    inline int fun() {
      return 111;
    }
    
    int main() {
      std::cout << "inline111: fun() = " << fun() << ", &fun = " << (void*) &fun;
      bar();
    }
  • inline222.cpp:

    #include <iostream>
    
    inline int fun() {
      return 222;
    }
    
    void bar() {
      std::cout << "inline222: fun() = " << fun() << ", &fun = " << (void*) &fun;
    }

  • กรณี A:

    รวบรวม :

    g++ -std=c++11 inline111.cpp inline222.cpp

    ผลผลิต :

    inline111: fun() = 111, &fun = 0x4029a0
    inline222: fun() = 111, &fun = 0x4029a0

    การสนทนา :

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

    2. Linker ไม่ได้บ่นเกี่ยวกับOne Definition Ruleตามที่fun()ได้ประกาศinlineไว้ อย่างไรก็ตามเนื่องจากinline111.cppเป็นหน่วยการแปลครั้งแรก (ซึ่งอันที่จริงเรียกfun()) การประมวลผลโดยคอมไพเลอร์ที่ instantiates คอมไพเลอร์fun()เมื่อมันเป็นครั้งแรกที่เรียกร้องการเผชิญหน้าในinline111.cpp หากคอมไพเลอร์ตัดสินใจที่จะไม่ขยายfun()การโทรออกจากที่อื่นในโปรแกรมของคุณ ( เช่นจากinline222.cpp ) การเรียกไปที่fun()จะเชื่อมโยงกับอินสแตนซ์ที่สร้างจากinline111.cpp เสมอ (การเรียกfun()ภายในinline222.cppอาจสร้างอินสแตนซ์ในหน่วยการแปลนั้น แต่มันจะยังไม่ถูกเชื่อมโยง) แน่นอนว่าเห็นได้ชัดจากการ&fun = 0x4029a0พิมพ์ที่เหมือนกัน

    3. ในที่สุดแม้จะมีinlineข้อเสนอแนะให้คอมไพเลอร์เพื่อขยายสายการบินfun()เดียว แต่ก็ไม่สนใจคำแนะนำของคุณอย่างสมบูรณ์ซึ่งชัดเจนเพราะfun() = 111ในทั้งสองบรรทัด


  • กรณี B:

    รวบรวม (แจ้งให้ทราบลำดับย้อนกลับ) :

    g++ -std=c++11 inline222.cpp inline111.cpp

    ผลผลิต :

    inline111: fun() = 222, &fun = 0x402980
    inline222: fun() = 222, &fun = 0x402980

    การสนทนา :

    1. กรณีนี้ยืนยันสิ่งที่ได้รับการกล่าวถึงในกรณี A

    2. ขอให้สังเกตจุดสำคัญว่าถ้าคุณแสดงความคิดเห็นออกมาเรียกร้องที่เกิดขึ้นจริงfun()ในinline222.cpp ( เช่นความคิดเห็นจากcout-statement ในinline222.cppสมบูรณ์) แล้วแม้จะมีการสั่งการสะสมของหน่วยงานการแปลของคุณfun()จะได้รับการ instantiated เมื่อมันเผชิญหน้าสายแรกในinline111.cppส่งผลในการพิมพ์ออกสำหรับกรณี Binline111: fun() = 111, &fun = 0x402980เป็น


  • กรณี C:

    รวบรวม (แจ้งให้ทราบ -O2) :

    g++ -std=c++11 -O2 inline222.cpp inline111.cpp

    หรือ

    g++ -std=c++11 -O2 inline111.cpp inline222.cpp

    ผลผลิต :

    inline111: fun() = 111, &fun = 0x402900
    inline222: fun() = 222, &fun = 0x402900

    การสนทนา :

    1. เป็นที่อธิบายไว้ที่นี่ , -O2การเพิ่มประสิทธิภาพการส่งเสริมให้คอมไพเลอร์จะจริงขยายฟังก์ชั่นที่สามารถ inlined (Notice ว่า-fno-inlineเป็นค่าเริ่มต้นโดยไม่มีตัวเลือกเพิ่มประสิทธิภาพ) ในฐานะที่เห็นได้ชัดจาก outprint ที่นี่ที่fun()ได้รับจริงขยายแบบอินไลน์ (ตามคำนิยามในที่โดยเฉพาะอย่างยิ่งหน่วยแปล) ส่งผลให้ในสองแตกต่างกัน fun()ลึกหนาบางพิมพ์ อย่างไรก็ตามเรื่องนี้ยังมีเพียงอินสแตนซ์ที่เชื่อมโยงทั่วโลกเพียงหนึ่งเดียวfun() (ตามที่กำหนดโดยมาตรฐาน) ตามที่เห็นได้ชัดจากการพิมพ์ที่เหมือนกัน &fun

8
คำตอบของคุณคือการโพสต์ตัวอย่างว่าทำไมภาษาทำให้inlineฟังก์ชั่นดังกล่าวเป็นพฤติกรรมที่ไม่ได้กำหนด
R Sahu

คุณควรเพิ่มกรณีที่การรวบรวมและการเชื่อมโยงแยกจากกันโดยแต่ละ.cppหน่วยเป็นหน่วยการแปลของตนเอง ควรเพิ่มเคสสำหรับ-fltoเปิด / ปิดใช้งาน
syockit

การอ้างอิง C ++ sais อย่างชัดเจน "หากฟังก์ชั่นอินไลน์หรือตัวแปร (ตั้งแต่ C ++ 17) ที่มีการเชื่อมโยงภายนอกถูกกำหนดไว้แตกต่างกันในหน่วยการแปลที่แตกต่างกันพฤติกรรมจะไม่ได้กำหนดไว้" ดังนั้นสิ่งที่คุณเขียนนั้นมีความเฉพาะเจาะจงของ GCC เนื่องจากเป็นผลข้างเคียงของการประสานกระบวนการรวบรวมและเชื่อมโยง นอกจากนี้โปรดสังเกตว่าสิ่งนี้อาจแตกต่างกันระหว่างรุ่น
Petr Fiedler

27

คุณยังคงต้องอินไลน์ฟังก์ชั่นของคุณอย่างชัดเจนเมื่อดำเนินการเฉพาะทางเทมเพลต (ถ้าความเชี่ยวชาญในไฟล์. h)


21

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

2) เสมอ ดู # 1

(แก้ไขเพื่อสะท้อนให้เห็นว่าคุณแบ่งคำถามเป็นสองคำถาม ... )


ใช่. อินไลน์เป็นเพียงคำใบ้ของคอมไพเลอร์และคุณสามารถเพิกเฉยได้ ทุกวันนี้คอมไพเลอร์น่าจะรู้ดีกว่าโปรแกรมเมอร์ซึ่งเป็นฟังก์ชั่นที่ดีที่สุดในการอินไลน์
Mark Byers

1
ใช่ แต่มันมีความเกี่ยวข้องน้อยกว่า - เพื่อให้ฟังก์ชั่นอินไลน์นั้นร่างกายจะต้องอยู่ในหน่วยการคอมไพล์เดียวกัน (ตัวอย่างเช่นในส่วนหัว) นั่นเป็นเรื่องธรรมดาในโปรแกรม C
Michael Kohne

1
การกำหนดเทมเพลตฟังก์ชั่นที่ไม่ใช่สมาชิก (เทมเพลตฟังก์ชั่นที่ไม่ใช่สมาชิกคงที่) ไม่จำเป็นต้องมีแบบอินไลน์ ดูกฎนิยามหนึ่งข้อ (3.2 / 5)
deft_code

2
-1: inlineยังจำเป็นต้องมีตัวอย่างเช่นเพื่อกำหนดฟังก์ชั่นในไฟล์ส่วนหัว (และที่จำเป็นสำหรับการอินไลน์ฟังก์ชันในหน่วยการคอมไพล์หลายหน่วย)
Melebius

1
@ Étienneที่ใช้งานเฉพาะ ตามมาตรฐานมีกฎข้อกำหนดหนึ่งข้อซึ่งหมายความว่าหากคุณรวมข้อกำหนดของฟังก์ชันในหน่วยการแปลหลายหน่วยอย่างไร้เดียงสาคุณจะได้รับข้อผิดพลาด แต่ถ้าฟังก์ชั่นนั้นมีตัวinlineระบุอินสแตนซ์ของมันจะถูกยุบโดยอัตโนมัติโดย linker และ ODR จะไม่ถูกใช้
Ruslan

12

เมื่อใดที่ฉันไม่ควรเขียนคำว่า 'อินไลน์' สำหรับฟังก์ชั่น / วิธีการใน C ++

หากมีการประกาศฟังก์ชันในส่วนหัวและกำหนดไว้ใน.cppไฟล์คุณไม่ควรเขียนคำหลัก

เมื่อใดที่คอมไพเลอร์ไม่ทราบว่าจะสร้างฟังก์ชัน / เมธอด 'inline' เมื่อใด

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

มันมีความสำคัญอย่างไรหากแอปพลิเคชันนั้นมีหลายเธรดเมื่อมีการเขียน 'inline' สำหรับฟังก์ชั่น / วิธีการ?

ไม่นั่นไม่สำคัญเลย


มีหลายกรณีที่เหมาะสมที่จะใช้อินไลน์ในไฟล์. cpp เช่นการใช้การปรับให้เหมาะสมกับโค้ดที่ใช้เฉพาะทั้งหมด
Robin Davies

@RobinDavies คำตอบที่ปรับปรุงแล้ว ดูเหมือนว่าคุณเข้าใจผิดในสิ่งที่ฉันต้องการจะเขียน
Johannes Schaub - litb

5
  • เมื่อใดที่คอมไพเลอร์ไม่ทราบว่าจะสร้างฟังก์ชัน / เมธอด 'inline' เมื่อใด

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

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

(รายละเอียดเพิ่มเติม: การจำลองทางคณิตศาสตร์ที่มีฟังก์ชั่นวิกฤติเล็กน้อยที่กำหนดไว้นอกคลาส, GCC 4.6.3 (g ++ -O3), ICC 13.1.0 (icpc -O3); การเพิ่มอินไลน์ไปยังจุดวิกฤติทำให้เกิดความเร็ว 6% พร้อมรหัส GCC)

ดังนั้นถ้าคุณมีคุณสมบัติ GCC 4.6 เป็นคอมไพเลอร์สมัยใหม่ผลลัพธ์ก็คือคำสั่งอินไลน์ยังคงมีความสำคัญหากคุณเขียนภาระงานของ CPU และรู้ว่าคอขวดเป็นอย่างไร


6
ฉันต้องการดูหลักฐานเพิ่มเติมเพื่อสำรองการอ้างสิทธิ์ของคุณ โปรดระบุรหัสที่คุณกำลังทดสอบพร้อมกับเอาต์พุตแอสเซมเบลอร์ที่มีและไม่มีคำหลักแบบอินไลน์ มีหลายสิ่งที่จะทำให้คุณได้รับประโยชน์จากประสิทธิภาพการทำงาน
void.pointer

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

@ void.pointer: ทำไมจึงยากที่จะเชื่อ? หากเครื่องมือเพิ่มประสิทธิภาพสมบูรณ์แล้วรุ่นใหม่ก็ไม่สามารถปรับปรุงประสิทธิภาพของโปรแกรมได้ แต่พวกเขาทำอย่างสม่ำเสมอ
MikeMB

3

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

โดยทั่วไปคอมไพเลอร์จะทำงานได้ดีในการตรวจจับ + เพิ่มประสิทธิภาพสิ่งต่าง ๆ เช่นนี้


7
ปัญหาคือว่าinlineมีความแตกต่างทางความหมายใน C ++ (เช่นในวิธีการปฏิบัติหลายคำจำกัดความ) ซึ่งมีความสำคัญในบางกรณี (เช่นแม่แบบ)
Pavel Minaev

4
อินไลน์ใช้เพื่อแก้ไขกรณีที่สัญลักษณ์มีหลายคำจำกัดความ อย่างไรก็ตามเทมเพลตได้รับการจัดการโดยภาษา ข้อยกเว้นประการหนึ่งคือฟังก์ชันเทมเพลตเฉพาะที่ไม่มีพารามิเตอร์แม่แบบอีกต่อไป (เทมเพลต <>) สิ่งเหล่านี้ได้รับการปฏิบัติเหมือนฟังก์ชั่นมากกว่าเทมเพลตดังนั้นจึงต้องใช้คำหลักแบบอินไลน์เพื่อเชื่อมโยง
deft_code

2

gcc โดยค่าเริ่มต้นจะไม่อินไลน์ฟังก์ชั่นใด ๆ เมื่อรวบรวมโดยไม่ได้เปิดใช้งานการเพิ่มประสิทธิภาพ ฉันไม่รู้เกี่ยวกับ visual studio - deft_code

ฉันตรวจสอบสิ่งนี้สำหรับ Visual Studio 9 (15.00.30729.01) โดยการคอมไพล์ด้วย / FAcs และดูรหัสประกอบ: คอมไพเลอร์สร้างการเรียกไปยังฟังก์ชั่นสมาชิกโดยไม่เปิดใช้งานการปรับให้เหมาะสมในโหมดดีบัก แม้ว่าฟังก์ชั่นจะถูกทำเครื่องหมายด้วย__forceinline จะไม่มีการสร้างโค้ดรันไทม์แบบอินไลน์


1
เปิดใช้งาน / แจ้งเตือนเกี่ยวกับฟังก์ชั่นที่มีการทำเครื่องหมายอินไลน์ แต่ไม่ได้รับการ inline
paulm

0

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


0

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

(แต่ดูมีเหตุผลใดที่จะไม่ใช้การเพิ่มประสิทธิภาพเวลาลิงก์ )


0

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

ควรใช้เมื่อใด:

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

มันอาจเป็นประโยชน์กับคุณที่จะรู้ว่านี่ไม่ใช่เรื่องจริง ระดับการปรับให้เหมาะสม -O0 ถึง - Ofast เป็นสิ่งที่กำหนดว่าฟังก์ชั่นจะถูกแทรกหรือไม่ อินไลน์ในการคอมไพล์ปกติ (-O0) จะไม่อินไลน์ฟังก์ชั่นไม่ว่าคุณจะใช้inlineหรือไม่ใน C และ C ++ C Inline: stackoverflow.com/a/62287072/7194773 C ++ แบบอินไลน์: stackoverflow.com/a/62230963/7194773
Lewis Kelsey

0

C ++ แบบอินไลน์จะแตกต่างไปC แบบอินไลน์

#include <iostream>
extern inline int i[];
int i [5];
struct c {
  int function (){return 1;} //implicitly inline
  static inline int j = 3; //explicitly inline
};
int main() {
  c j;
  std::cout << i;
}

inlineด้วยตัวของมันเองจะมีผลกับคอมไพเลอร์แอสเซมเบลอร์และลิงเกอร์ มันเป็นคำสั่งให้คอมไพเลอร์พูดเพียงปล่อยสัญลักษณ์สำหรับฟังก์ชั่น / ข้อมูลนี้ถ้ามันถูกใช้ในหน่วยการแปลและถ้าเป็นเช่นนั้นเช่นเดียวกับวิธีการเรียนบอกผู้ประกอบเพื่อเก็บไว้ในส่วน.section .text.c::function(),"axG",@progbits,c::function(),comdatหรือ.section .bss.i,"awG",@nobits,i,comdatข้อมูล

สิ่งต่อไป.section name, "flags"MG, @type, entsize, GroupName[, linkage]นี้ .text.c::function()ยกตัวอย่างเช่นชื่อส่วนคือ axGหมายถึงส่วนที่สามารถปันส่วนใช้งานได้และในกลุ่มคือชื่อกลุ่มจะถูกระบุ (และไม่มีแฟล็ก M เพื่อไม่ให้ระบุ entsize); @progbitsหมายถึงส่วนที่มีข้อมูลและไม่ว่างเปล่า c::function()เป็นชื่อกลุ่มและกลุ่มมีcomdatการเชื่อมโยงหมายถึงว่าในทุกวัตถุไฟล์ทุกส่วนที่พบกับชื่อกลุ่มนี้ที่ติดแท็กด้วย comdat จะถูกลบออกจากการปฏิบัติการขั้นสุดท้ายยกเว้น 1 เช่นคอมไพเลอร์ทำให้แน่ใจว่ามีเพียงหนึ่งคำจำกัดความในหน่วยการแปลแล้วบอกผู้ประกอบ มันอยู่ในกลุ่มของตัวเองในไฟล์วัตถุ (1 ส่วนใน 1 กลุ่ม) จากนั้นตัวเชื่อมโยงจะตรวจสอบให้แน่ใจว่าหากไฟล์วัตถุใด ๆ มีกลุ่มที่มีชื่อเหมือนกันให้รวมเพียงหนึ่งไฟล์ใน. exe ขั้นสุดท้าย ตอนนี้ความแตกต่างระหว่างinlineและไม่ได้ใช้งานinlineจะปรากฏแก่แอสเซมเบลอร์และเป็นผลให้ linker เพราะมันไม่ได้ถูกจัดเก็บในปกติ.dataหรือ.textอื่น ๆ เนื่องจากคำสั่ง

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

static inlineที่ขอบเขตไฟล์มีผลกับคอมไพเลอร์เท่านั้น มันหมายถึงคอมไพเลอร์: ปล่อยสัญลักษณ์สำหรับฟังก์ชั่น / ข้อมูลนี้ถ้ามันถูกใช้ในหน่วยการแปลและทำเช่นนั้นเป็นสัญลักษณ์แบบคงที่ปกติ สำหรับแอสเซมเบลอร์ตอนนี้ไม่มีความแตกต่างระหว่างstaticและstatic inline

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

extern inline int i[];
extern int i[]; //allowed repetition of declaration with incomplete type, inherits inline property
extern int i[5]; //declaration now has complete type
extern int i[5]; //allowed redeclaration if it is the same complete type or has not yet been completed
extern int i[6]; //error, redeclaration with different complete type
int i[5]; //definition, must have complete type and same complete type as the declaration if there is a declaration with a complete type

inline int i[5]ทั้งหมดที่กล่าวมาไม่มีสายข้อผิดพลาดที่จะพังทลายลงมา เห็นได้ชัดว่าถ้าคุณทำextern inline int i[] = {5};แล้วexternจะถูกละเว้นเนื่องจากคำจำกัดความที่ชัดเจนผ่านการมอบหมาย

inlineบนเนมสเปซให้ดูสิ่งนี้และสิ่งนี้


-1

เมื่อพัฒนาและแก้ไขจุดบกพร่องของรหัสให้inlineออกไป มันซับซ้อนการแก้จุดบกพร่อง

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

Expending ชนิดของความคิดเกี่ยวกับการเพิ่มประสิทธิภาพการทำงานก่อนที่จะเสร็จสิ้นขั้นตอนวิธีการนี้คือการเพิ่มประสิทธิภาพก่อนวัยอันควร


12
inlineฟังก์ชั่นโดยทั่วไปจะไม่ inline เว้นแต่การรวบรวมกับการเพิ่มประสิทธิภาพดังนั้นจึงไม่ส่งผลกระทบต่อการแก้จุดบกพร่องในทางใดทางหนึ่ง โปรดจำไว้ว่ามันเป็นคำใบ้ไม่ใช่ความต้องการ
Pavel Minaev

3
gcc โดยค่าเริ่มต้นจะไม่อินไลน์ฟังก์ชั่นใด ๆ เมื่อรวบรวมโดยไม่ได้เปิดใช้งานการเพิ่มประสิทธิภาพ ฉันไม่รู้เกี่ยวกับ visual studio
deft_code

ฉันทำงานในโครงการ g ++ ขนาดใหญ่ที่เปิดใช้งานการดีบัก บางทีตัวเลือกอื่น ๆ อาจป้องกันมันinlineได้ มันเป็นไปไม่ได้ที่จะกำหนดจุดพักที่มีความหมายในพวกเขา
wallyk

2
การเปิดใช้งานการดีบักไม่หยุดการ inline ใน gcc หากการเพิ่มประสิทธิภาพใด ๆ ที่เปิดใช้งาน (-O1 หรือสูงกว่า) ดังนั้น gcc จะพยายามอินไลน์กรณีที่ชัดเจนที่สุด ตามเนื้อผ้า GDB มีช่วงเวลาที่ยากลำบากกับจุดพักและตัวสร้างโดยเฉพาะอย่างยิ่งตัวสร้างแบบอินไลน์ แต่ที่ได้รับการแก้ไขในรุ่นล่าสุด (อย่างน้อย 6.7 หรืออาจเร็วกว่านี้)
deft_code

2
การเพิ่มinlineจะไม่ทำอะไรเพื่อปรับปรุงโค้ดในคอมไพเลอร์สมัยใหม่ซึ่งสามารถคิดได้ว่าจะอินไลน์หรือไม่ด้วยตัวเอง
David Thornley

-1

เมื่อหนึ่งควรอินไลน์:

1. เมื่อต้องการหลีกเลี่ยงค่าใช้จ่ายในสิ่งที่เกิดขึ้นเมื่อฟังก์ชั่นถูกเรียกเช่นพารามิเตอร์ผ่านการควบคุมการถ่ายโอนการควบคุมผลตอบแทน ฯลฯ

2. ฟังก์ชั่นควรมีขนาดเล็กเรียกบ่อยและการสร้างอินไลน์นั้นมีประโยชน์จริง ๆ ตั้งแต่กฎ 80-20 ลองสร้างฟังก์ชั่นเหล่านั้นแบบอินไลน์ซึ่งมีผลกระทบสำคัญต่อประสิทธิภาพของโปรแกรม

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


"อินไลน์เป็นเพียงการร้องขอให้คอมไพเลอร์คล้ายกับการลงทะเบียน" พวกเขาคล้ายกันเพราะไม่มีการร้องขอหรือไม่มีส่วนเกี่ยวข้องกับการปรับให้เหมาะสม inlineได้สูญเสียสถานะเป็นคำแนะนำการปรับให้เหมาะสมและคอมไพเลอร์ส่วนใหญ่จะใช้เพื่อให้อนุญาตสำหรับคำจำกัดความหลายคำเท่านั้น - ตามที่ควรจะเป็น IMO ยิ่งกว่านั้นตั้งแต่ C ++ 11 registerได้ถูกคัดค้านอย่างเต็มที่สำหรับความหมายก่อนหน้าของ 'ฉันรู้ดีกว่าคอมไพเลอร์ถึงวิธีการปรับให้เหมาะสม': ตอนนี้เป็นเพียงคำสงวนที่ไม่มีความหมายในปัจจุบัน
underscore_d

@underscore_d: Gcc ยังคงฟังในinlineระดับหนึ่ง
MikeMB

-1

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

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

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

นิยามฟังก์ชันในนิยามคลาสเป็นนิยามฟังก์ชันอินไลน์แม้ว่าจะไม่มีการใช้ตัวระบุอินไลน์

ต่อไปนี้เป็นตัวอย่างซึ่งใช้ประโยชน์จากฟังก์ชั่นอินไลน์เพื่อส่งกลับจำนวนสูงสุดสองตัวเลข

#include <iostream>

using namespace std;

inline int Max(int x, int y) { return (x > y)? x : y; }

// Main function for the program
int main() {
   cout << "Max (100,1010): " << Max(100,1010) << endl;

   return 0;
}

สำหรับข้อมูลเพิ่มเติมโปรดดูที่นี่

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