ตรวจสอบให้แน่ใจว่าส่วนหัวจะถูกรวมไว้อย่างชัดเจนในไฟล์ CPP


10

ฉันคิดว่าเป็นเรื่องดี#includeสำหรับส่วนหัวสำหรับประเภทใด ๆ ที่ใช้ในไฟล์ CPP โดยไม่คำนึงถึงสิ่งที่รวมอยู่ในไฟล์ HPP ดังนั้นฉันจึงอาจเป็นได้#include <string>ทั้ง HPP และ CPP แม้ว่าฉันจะสามารถรวบรวมได้หากฉันข้ามใน CPP ด้วยวิธีนี้ฉันไม่ต้องกังวลว่า HPP ของฉันจะใช้การประกาศล่วงหน้าหรือไม่

มีเครื่องมือใดที่สามารถบังคับใช้#includeรูปแบบการเข้ารหัสนี้ได้หรือไม่? ฉันควรบังคับใช้รูปแบบการเข้ารหัสนี้หรือไม่

เนื่องจากตัวประมวลผลล่วงหน้า / คอมไพเลอร์ไม่สนใจว่า#includeจะมาจาก HPP หรือ CPP ฉันจึงไม่ได้รับคำติชมถ้าฉันลืมทำตามสไตล์นี้

คำตอบ:


7

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

กฎที่พบบ่อยมากสำหรับไฟล์ส่วนหัวคือพวกเขาจะต้องยืนด้วยตนเอง ไฟล์ส่วนหัวต้องไม่กำหนดให้ไฟล์ส่วนหัวอื่น ๆ รวม #included ก่อนที่จะรวมส่วนหัวที่เป็นปัญหา นี่คือข้อกำหนดที่สามารถทดสอบได้ รับส่วนหัวสุ่มบางส่วนfoo.hhต่อไปนี้ควรรวบรวมและเรียกใช้:

#include "foo.hh"
int main () {
   return 0;
}

กฎนี้มีผลที่ตามมาเกี่ยวกับการใช้คลาสอื่นในบางหัวข้อ บางครั้งผลกระทบเหล่านั้นสามารถหลีกเลี่ยงได้โดยการส่งต่อประกาศคลาสอื่น ๆ เหล่านั้น ไม่สามารถทำได้ด้วยคลาสไลบรารีมาตรฐานจำนวนมาก ไม่มีทางที่จะไปข้างหน้าประกาศ instantiation แม่แบบเช่นไม่ได้หรือstd::string std::vector<SomeType>คุณต้องใช้#includeส่วนหัว STL เหล่านั้นในส่วนหัวแม้ว่าการใช้ชนิดเท่านั้นจะเป็นอาร์กิวเมนต์ของฟังก์ชัน

ปัญหาอื่นคือสิ่งที่คุณลากเข้ามาโดยบังเอิญตัวอย่าง: พิจารณาสิ่งต่อไปนี้:

ไฟล์ foo.cc:

#include "foo.hh"
#include "bar.hh"

void Foo::Foo () : bar() { /* body elided */ }

void Foo::do_something (int item) {
   ...
   bar.add_item (item);
   ...
}

นี่barเป็นชั้นข้อมูลสมาชิกที่เป็นประเภทFoo Barคุณได้ทำสิ่งที่ถูกต้องที่นี่และได้ # รวม bar.hh Fooแม้ว่าที่จะต้องได้รับการรวมอยู่ในส่วนหัวที่กำหนดระดับ แต่คุณยังไม่ได้รวมสิ่งที่ใช้โดยและBar::Bar() Bar::add_item(int)มีหลายกรณีที่การเรียกเหล่านี้อาจส่งผลให้มีการอ้างอิงภายนอกเพิ่มเติม

หากคุณวิเคราะห์foo.oด้วยเครื่องมือเช่นnmนั้นจะปรากฏว่าฟังก์ชั่นในการเรียกร้องทุกชนิดของสิ่งที่คุณยังไม่ได้ดำเนินการที่เหมาะสมfoo.cc #includeดังนั้นคุณควรเพิ่ม#includeคำสั่งสำหรับการอ้างอิงภายนอกโดยบังเอิญfoo.cc? คำตอบนั้นไม่แน่นอน ปัญหาคือว่ามันยากมากที่จะแยกแยะฟังก์ชั่นเหล่านั้นที่เรียกว่าบังเอิญจากฟังก์ชั่นที่เรียกโดยตรง


2

ฉันควรบังคับใช้รูปแบบการเข้ารหัสนี้หรือไม่

อาจจะไม่. กฎของฉันคือ: การรวมไฟล์ส่วนหัวไม่สามารถสั่งซื้อได้

คุณสามารถตรวจสอบได้ค่อนข้างง่ายด้วยกฎง่ายๆที่ไฟล์แรกรวมโดย xc คือ xh


1
คุณสามารถทำอย่างละเอียดเกี่ยวกับเรื่องนี้? ฉันไม่เห็นว่าสิ่งนั้นจะยืนยันความเป็นอิสระของคำสั่งซื้อได้อย่างไร
detly

1
มันไม่ได้จริงๆอิสระเพื่อรับประกัน - มันก็ทำให้มั่นใจได้ว่าจะทำงานได้โดยไม่ต้องมีบางอย่างก่อน#include "x.h" นั่นเพียงพอที่ดีถ้าคุณทำไม่ได้ทำผิดกฎ#include #define
kevin cline

1
อ้อเข้าใจแล้ว. ยังคงเป็นความคิดที่ดี
detly

2

หากคุณต้องการบังคับใช้กฎที่ไฟล์ส่วนหัวโดยเฉพาะต้องยืนด้วยตนเองคุณสามารถใช้เครื่องมือที่คุณมีอยู่แล้ว สร้าง makefile พื้นฐานที่รวบรวมไฟล์ส่วนหัวแต่ละไฟล์แยกกัน แต่ไม่สร้างไฟล์อ็อบเจ็กต์ คุณจะสามารถระบุโหมดที่จะรวบรวมไฟล์ส่วนหัวใน (โหมด C หรือ C ++) และตรวจสอบว่าสามารถยืนได้ด้วยตนเอง คุณสามารถตั้งสมมติฐานที่สมเหตุสมผลว่าเอาต์พุตไม่ได้มีผลบวกปลอมใด ๆ การอ้างอิงที่ต้องการทั้งหมดจะถูกประกาศและผลลัพธ์นั้นถูกต้อง

หากคุณใช้ IDE คุณอาจยังสามารถทำได้โดยไม่ต้องใช้ makefile (ขึ้นอยู่กับ IDE ของคุณ) เพียงแค่สร้างโครงการเพิ่มเติมเพิ่มไฟล์ส่วนหัวที่คุณต้องการตรวจสอบและเปลี่ยนการตั้งค่าเพื่อรวบรวมเป็นไฟล์ C หรือ C ++ ใน MSVC เช่นคุณจะเปลี่ยนการตั้งค่า "ประเภทรายการ" ใน "คุณสมบัติการกำหนดค่า -> ทั่วไป"


1

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

ปัญหาเกี่ยวกับการเขียนเครื่องมือเช่นนี้คือมันรายงานผลลัพธ์ที่ผิดได้ง่ายมากดังนั้นฉันจึงประเมินความได้เปรียบสุทธิของเครื่องมือดังกล่าวให้ใกล้เคียงกับศูนย์

วิธีเดียวที่เครื่องมือดังกล่าวสามารถใช้งานได้คือหากสามารถรีเซ็ตตารางสัญลักษณ์เป็นเพียงเนื้อหาของไฟล์ส่วนหัวที่ประมวลผลแล้ว แต่คุณพบปัญหาที่ส่วนหัวที่สร้าง API ภายนอกของไลบรารีมอบหมายการประกาศจริงให้ ส่วนหัวภายใน
ตัวอย่างเช่น<string>ในการใช้งาน GCC libc ++ ไม่ได้ประกาศอะไร แต่มันรวมถึงส่วนหัวภายในที่มีการประกาศจริง หากเครื่องมือรีเซ็ตตารางสัญลักษณ์เป็นเพียงแค่สิ่งที่ถูกประกาศด้วย<string>ตัวของมันเองก็จะไม่มีอะไร
คุณอาจมีเครื่องมือที่แยกความแตกต่างระหว่าง#include ""และ#include <>แต่ไม่ช่วยถ้าห้องสมุดภายนอกใช้#include ""เพื่อรวมส่วนหัวภายในใน API


1

ไม่ได้รับ#Pragma onceสิ่งนี้ใช่ไหม คุณสามารถรวมสิ่งที่หลาย ๆ ครั้งตามที่คุณต้องการไม่ว่าจะโดยตรงหรือผ่านทางล่ามโซ่รวมถึงและตราบใดที่มีการ#Pragma onceติดกันของพวกเขาส่วนหัวจะรวมเพียงครั้งเดียว

ในการบังคับใช้นั้นบางทีคุณอาจสร้างระบบการสร้างที่รวมส่วนหัวด้วยตัวมันเองด้วยฟังก์ชั่นหลักจำลองบางอย่างเพื่อให้แน่ใจว่ามันจะรวบรวม #ifdefโซ่รวมถึงผลลัพธ์ที่ดีที่สุดด้วยวิธีการทดสอบนั้น


1

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


คุณอธิบายได้ไหมว่าวิธีนี้จะ "ลดระยะเวลาการรวบรวมอย่างมีนัยสำคัญ" ได้อย่างไร
Mawg พูดว่าคืนสถานะโมนิก้า

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

ด้วยยามรวมฉันอาจ quesiton "vitalanbtly" แต่ฉันคิดว่าการเข้าถึงดิสก์ (ใน oorder เพื่อค้นหา gauards inlcude เหล่านั้น) คือ "ช้า" ดังนั้นจะยอมยกประเด็น, ขอบคุณสำหรับการชี้แจง
Mawg พูดว่าคืนสถานะโมนิก้า

0

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

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

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


3
ถ้าคุณปล่อยให้รวมถึงการออกจากหัวแล้วรวมคำสั่งซื้อเริ่มที่จะมีความสำคัญ ... และฉันแน่นอนต้องการหลีกเลี่ยงการว่า
M. Dudley

1
-1: สร้างฝันร้ายที่พึ่งพา การเพิ่มประสิทธิภาพให้กับ xh อาจต้องการการเปลี่ยนแปลงในไฟล์. cpp ทุกครั้งที่มี xh
kevin cline

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