คำสั่งใดควรรวมไฟล์ไว้เช่นอะไรคือสาเหตุของการรวมส่วนหัวหนึ่งหน้าไว้ด้วยกัน
ตัวอย่างเช่นไฟล์ระบบ, STL และ Boost ไปก่อนหรือหลังไฟล์รวมในระบบหรือไม่
คำสั่งใดควรรวมไฟล์ไว้เช่นอะไรคือสาเหตุของการรวมส่วนหัวหนึ่งหน้าไว้ด้วยกัน
ตัวอย่างเช่นไฟล์ระบบ, STL และ Boost ไปก่อนหรือหลังไฟล์รวมในระบบหรือไม่
คำตอบ:
ฉันไม่คิดว่าจะมีคำสั่งแนะนำตราบใดที่มันรวบรวม! สิ่งที่น่ารำคาญก็คือเมื่อส่วนหัวบางส่วนต้องรวมส่วนหัวอื่นก่อน ... นั่นเป็นปัญหาของส่วนหัวเองไม่ใช่ลำดับของการรวม
ความชอบส่วนตัวของฉันคือไปจากท้องถิ่นสู่ระดับโลกแต่ละส่วนย่อยตามลำดับตัวอักษรคือ:
เหตุผลของฉันสำหรับ 1. คือควรพิสูจน์ว่าแต่ละส่วนหัว (ซึ่งมี cpp) สามารถเป็น#include
d โดยไม่มีข้อกำหนดเบื้องต้น (terminus technicus: ส่วนหัวคือ "มีอยู่ในตัวเอง") และที่เหลือก็ดูเหมือนจะไหลจากที่นั่นอย่างมีเหตุผล
สิ่งสำคัญที่ต้องจำไว้คือส่วนหัวของคุณไม่ควรขึ้นอยู่กับส่วนหัวอื่น ๆ ที่ถูกรวมไว้ก่อน วิธีหนึ่งในการประกันนี้คือการรวมส่วนหัวของคุณก่อนที่ส่วนหัวอื่น ๆ
"การคิดใน C ++" โดยเฉพาะกล่าวถึงสิ่งนี้โดยอ้างอิงจาก Lakos '"การออกแบบซอฟต์แวร์ C ++ ขนาดใหญ่":
ข้อผิดพลาดในการใช้งานแฝงสามารถหลีกเลี่ยงได้โดยตรวจสอบให้แน่ใจว่าไฟล์. h ของคอมโพเนนต์แยกวิเคราะห์ด้วยตัวเอง - โดยไม่มีการประกาศหรือคำจำกัดความภายนอกที่ระบุ ... รวมถึงไฟล์. h เป็นบรรทัดแรกของไฟล์. c ข้อมูลที่อยู่ในอินเทอร์เฟซทางกายภาพของส่วนประกอบหายไปจากไฟล์. h (หรือหากมีอยู่คุณจะพบข้อมูลนั้นทันทีที่คุณพยายามรวบรวมไฟล์. c)
กล่าวคือรวมไว้ในลำดับต่อไปนี้:
หากส่วนหัวใดมีปัญหาในการรวมอยู่ในคำสั่งซื้อนี้ให้แก้ไข (ถ้าเป็นของคุณ) หรือไม่ใช้ ห้องสมุด Boycott ที่ไม่เขียนหัวเรื่องที่สะอาด
คู่มือสไตล์ C ++ ของ Google ให้เหตุผลว่าเกือบจะตรงกันข้ามโดยไม่มีเหตุผลใด ๆ เลย โดยส่วนตัวแล้วผมชอบวิธีการของลอส
ฉันปฏิบัติตามกฎง่ายๆสองข้อที่หลีกเลี่ยงปัญหาส่วนใหญ่:
ฉันทำตามแนวทางของ:
ในคำอื่น ๆ :
#include <stdio.h>
#include <string.h>
#include "btree.h"
#include "collect_hash.h"
#include "collect_arraylist.h"
#include "globals.h"
ถึงแม้ว่าการเป็นแนวทางเป็นเรื่องส่วนตัว ในทางกลับกันฉันบังคับใช้อย่างเหนียวแน่นถึงแม้จะให้ไฟล์ส่วนหัว 'wrapper' พร้อมด้วยยามรวมและจัดกลุ่มรวมหากนักพัฒนาบุคคลที่สามที่น่ารังเกียจบางคนไม่สมัครเป็นสมาชิกวิสัยทัศน์ของฉัน :-)
เพื่อเพิ่มอิฐของฉันเองบนผนัง
ดังนั้นฉันมักจะไปเช่นนี้:
// myproject/src/example.cpp
#include "myproject/example.h"
#include <algorithm>
#include <set>
#include <vector>
#include <3rdparty/foo.h>
#include <3rdparty/bar.h>
#include "myproject/another.h"
#include "myproject/specific/bla.h"
#include "detail/impl.h"
แต่ละกลุ่มคั่นด้วยบรรทัดว่างจากกลุ่มถัดไป:
นอกจากนี้โปรดทราบว่านอกเหนือจากส่วนหัวของระบบแต่ละไฟล์อยู่ในโฟลเดอร์ที่มีชื่อเนมสเปซเพียงเพราะง่ายต่อการติดตามด้วยวิธีนี้
#define
ที่ทำให้รหัสอื่นสับสน) และเพื่อป้องกันการพึ่งพาโดยนัย ตัวอย่างเช่นหากไฟล์ส่วนหัวของรหัสฐานของเราfoo.h
ขึ้นอยู่กับ<map>
ทุกที่ แต่มันถูกใช้ใน.cc
ไฟล์<map>
เกิดขึ้นเพื่อรวมไว้แล้วเราอาจจะไม่สังเกตเห็น จนกว่าจะมีคนพยายามรวมfoo.h
โดยไม่รวม<map>
ก่อน แล้วพวกเขาก็จะรำคาญ
.h
มีอย่างน้อยหนึ่ง.cpp
ที่รวมไว้ก่อน (แน่นอนในรหัสส่วนตัวของฉันการทดสอบหน่วยที่เกี่ยวข้องรวมไว้ก่อน ) เกี่ยวกับการไม่ได้รับอิทธิพลหากส่วนใดส่วนหนึ่งรวมถึงส่วนหัว<map>
ทั้งหมดที่รวมอยู่ในภายหลังนั้นจะได้รับอิทธิพลอยู่แล้วดังนั้นจึงดูเหมือนว่าการต่อสู้จะแพ้ไป
Header corresponding to this cpp file first (sanity check)
ฉันอยากจะรู้ว่าเหตุผลที่อยู่เบื้องหลังจุดหนึ่งคือ มีสิ่งใดเป็นพิเศษหรือไม่หาก#include "myproject/example.h"
ถูกย้ายไปยังจุดสิ้นสุดของการรวมทั้งหมด?
ฉันแนะนำ:
และแน่นอนเรียงตามตัวอักษรภายในแต่ละส่วนหากเป็นไปได้
ใช้การประกาศไปข้างหน้าเสมอเพื่อหลีกเลี่ยงการที่ไม่จำเป็น#include
ในไฟล์ส่วนหัวของคุณ
ฉันค่อนข้างแน่ใจว่านี่ไม่ใช่วิธีปฏิบัติที่แนะนำที่ใดก็ได้ในโลกที่มีสติ แต่ฉันชอบระบบบรรทัดรวมขึ้นด้วยความยาวชื่อไฟล์เรียงตามศัพท์ภายในความยาวเดียวกัน ชอบมาก
#include <set>
#include <vector>
#include <algorithm>
#include <functional>
ฉันคิดว่าเป็นความคิดที่ดีที่จะรวมส่วนหัวของคุณไว้ต่อหน้าคนอื่นเพื่อหลีกเลี่ยงความอับอายของการพึ่งพาคำสั่งซื้อ
windows.h
บางทีแม้กระทั่ง
สิ่งนี้ไม่ใช่เรื่องส่วนตัว ตรวจสอบให้แน่ใจว่าส่วนหัวของคุณไม่พึ่งพาการ#include
เรียงตามลำดับ คุณสามารถมั่นใจได้ว่าไม่สำคัญว่าคุณจะมีส่วนหัวลำดับ STL หรือ Boost
ก่อนอื่นให้รวมส่วนหัวที่เกี่ยวข้องกับ. cpp ... ในคำอื่น ๆsource1.cpp
ควรรวมไว้source1.h
ก่อนรวมสิ่งอื่นใด ข้อยกเว้นเดียวที่ฉันคิดได้คือเมื่อใช้ MSVC กับส่วนหัวที่รวบรวมไว้ล่วงหน้าซึ่งในกรณีนี้คุณจะถูกบังคับให้รวมstdafx.h
ก่อนสิ่งอื่นใด
การใช้เหตุผล: การรวมไฟล์source1.h
ก่อนหน้าอื่น ๆ ทำให้มั่นใจได้ว่าไฟล์สามารถทำงานได้อย่างอิสระโดยไม่ต้องพึ่งพา หากsource1.h
ใช้การอ้างอิงในภายหลังคอมไพเลอร์จะแจ้งเตือนคุณทันทีเพื่อเพิ่มการประกาศไปข้างหน้าที่จำเป็นsource1.h
จะใช้เวลาในการพึ่งพาในวันต่อมาคอมไพเลอร์จะแจ้งเตือนทันทีที่คุณสามารถเพิ่มต้องประกาศไปข้างหน้าเพื่อสิ่งนี้จะช่วยให้มั่นใจได้ว่าส่วนหัวสามารถรวมอยู่ในลำดับใดก็ได้โดยผู้ติดตาม
ตัวอย่าง:
source1.h
class Class1 {
Class2 c2; // a dependency which has not been forward declared
};
source1.cpp
#include "source1.h" // now compiler will alert you saying that Class2 is undefined
// so you can forward declare Class2 within source1.h
...
ผู้ใช้ MSVC:ฉันขอแนะนำอย่างยิ่งให้ใช้ส่วนหัวที่รวบรวมไว้ล่วงหน้า ดังนั้นย้ายทั้งหมด#include
สั่งสำหรับส่วนหัวมาตรฐาน (และส่วนหัวอื่น ๆ ที่ไม่เคยไปมีการเปลี่ยนแปลง) stdafx.h
เพื่อ
รวมจากส่วนที่เฉพาะเจาะจงมากที่สุดถึงน้อยที่สุดเริ่มต้นด้วย. hpp ที่เกี่ยวข้องสำหรับ. cpp หากมีอยู่จริง ด้วยวิธีนี้การอ้างอิงที่ซ่อนอยู่ใด ๆ ในไฟล์ส่วนหัวที่ไม่เพียงพอจะถูกเปิดเผย
ปัญหานี้ซับซ้อนโดยใช้ส่วนหัวที่รวบรวมไว้ล่วงหน้า วิธีหนึ่งในการทำเช่นนี้คือไม่ต้องทำให้คอมไพเลอร์เฉพาะโครงการของคุณคือใช้ส่วนหัวโครงการหนึ่งเนื่องจากส่วนหัวของไฟล์ที่คอมไพล์แล้ว
มันเป็นคำถามที่ยากในโลก C / C ++ ที่มีองค์ประกอบมากมายเกินกว่ามาตรฐาน
ฉันคิดว่าคำสั่งไฟล์ส่วนหัวไม่ใช่ปัญหาร้ายแรงตราบใดที่มันคอมไพล์เช่น squelart กล่าว
ความคิดของฉันคือ: หากไม่มีความขัดแย้งของสัญลักษณ์ในส่วนหัวทั้งหมดคำสั่งใด ๆ ก็โอเคและปัญหาการพึ่งพาส่วนหัวสามารถแก้ไขได้ในภายหลังโดยการเพิ่ม #include บรรทัดลงในข้อบกพร่อง. h
ความยุ่งยากที่แท้จริงเกิดขึ้นเมื่อส่วนหัวบางส่วนเปลี่ยนการกระทำของมัน (โดยการตรวจสอบ #if เงื่อนไข) ตามสิ่งที่ส่วนหัวอยู่ด้านบน
ตัวอย่างเช่นใน stddef.h ใน VS2005 มี:
#ifdef _WIN64
#define offsetof(s,m) (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
ตอนนี้ปัญหา: ถ้าฉันมีส่วนหัวที่กำหนดเอง ("custom.h") ที่จำเป็นต้องใช้กับคอมไพเลอร์จำนวนมากรวมถึงบางส่วนที่เก่ากว่าที่ไม่ได้ให้offsetof
ไว้ในส่วนหัวของระบบฉันควรเขียนในส่วนหัวของฉัน:
#ifndef offsetof
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
และให้แน่ใจว่าได้แจ้งให้ผู้ใช้ทราบ#include "custom.h"
หลังจากส่วนหัวของระบบทั้งหมดมิฉะนั้นบรรทัดoffsetof
ใน stddef.h จะยืนยันข้อผิดพลาดในการกำหนดแมโครซ้ำ
เราสวดอ้อนวอนไม่ให้พบกรณีเช่นนี้ในอาชีพของเราอีกต่อไป