هل يجب علي استخدام رأس واحد لتضمين جميع رؤوس مكتبة ثابتة؟

StackOverflow https://stackoverflow.com/questions/2226927

  •  19-09-2019
  •  | 
  •  

سؤال

لدي مكتبة ثابتة أقيم فيها في C ++. لقد فصلت ذلك إلى العديد من الملفات الرأسية والملفات المصدر. أنا أتساءل عما إذا كان من الأفضل أن تتضمن جميع الرؤوس أن عميل المكتبة قد يحتاجه في ملف رأس واحد يمكن أن يتضمن بدوره في التعليمات البرمجية المصدرية أو ما عليك سوى إدراج الرؤوس التي يحتاجونها فقط؟ هل سيؤدي ذلك إلى أن يكون الكود غير ضروري؟ لم أكن متأكدا مما إذا كانت الفصول أو الوظائف التي لا تعتاد على منتجاتها ستظل تجميعها في منتجاتها.

شكرا على اي مساعدة.

هل كانت مفيدة؟

المحلول

بشكل عام، عند ربط الملف القابل للتنفيذ النهائي، سيتم دمج الرموز والوظائف التي يستخدمها البرنامج فقط من قبل البرنامج. أنت تدفع فقط لما تستخدمه. على الأقل، كل هذا هو كيف يبدو أن Toolchain GCC تعمل بالنسبة لي. لا أستطيع التحدث عن جميع هذه الأدوات.

إذا كان يجب على العميل دائما تضمين نفس مجموعة ملفات الرأس، فما أعتقد أنه من الجيد تقديم ملف رأس "ماجستير" يتضمن آخرين، من أجل الراحة. ولكن جعله حتى يمكن للعميل اختيار أيضا تضمين ما هو مطلوب فقط.

للحد من تجميع أوقات الترجمة في المشاريع الكبيرة، فمن الممارسات الشائعة أن تضم أقل قدر من الرؤوس قدر الإمكان لجعل وحدة تجميعها.

نصائح أخرى

ضع في اعتبارك أن كل ملف مصدر تقوم بتجميعه يتضمن استدعاء مستقل للمترجم. مع كل الاحتكار، يتعين على المحول البرمجي أن يقرأ في كل ملف رأس مضمون، وتحليله، وبناء جدول رمز.

عند استخدام واحدة من هذه "تضمين ملفات رأس العالم" في الكثير من الملفات المصدر الخاصة بك، يمكن أن تؤثر بشكل كبير على وقت الإنشاء الخاص بك.

هناك طرق لتخفيف هذا؛ على سبيل المثال، لدى Microsoft ميزة رأس مسبقة أن تحفظ أساسا جدول الرموز للكواسيات اللاحقة لاستخدامها.

هناك اعتبار آخر على الرغم من ذلك. إذا كنت سأستخدم فئة WhizzoString الخاصة بك، لا يجب أن يكون لديك رؤوس مثبتة للصابون، OpenGL، وما الذي لديك. في الواقع، أنا أفضل أن تشمل whizzostring.h الرؤوس فقط لأنواع ورموز هي جزء من الواجهة العامة (أي الأشياء التي انا سوف تحتاج كمستخدم لصفك).

قدر الإمكان، يجب أن تحاول التحول بما يتضمن من whizzostring.h إلى whizzostring.cpp:

نعم:

// Only include the stuff needed for this class
#include "foo.h"  // Foo class
#include "bar.h"  // Bar class

public class WhizzoString
{
    private Foo   m_Foo;
    private Bar * m_pBar;
       .
       .
       .
}

أفضل:

// Only include the stuff needed by the users of this class
#include "foo.h"  // Foo class

class Bar; // Forward declaration

public class WhizzoString
{
    private Foo   m_Foo;
    private Bar * m_pBar;
       .
       .
       .
}

إذا اضطر مستخدمي فئتك إلى خلق أو استخدام نوع شريط، ولا تحتوي الفئة على أي حالات شريط، فقد تكون كافية لتوفير إعلان إلى الأمام فقط من شريط في ملف الرأس (whizzostring.cpp سيكون لديه #include "bar.h"). هذا يعني أن أي شخص يشمل whizzostring.h يمكن تجنب ذلك

ماذا عن إعطاء كل الخيارات:

#include <library.hpp> // include everything
#include <library/module.hpp> // only single module

بهذه الطريقة ليس لديك ملف ضخمة واحدة، وللملفات المنفصلة الخاصة بك، يتم تكديسها بدقة واحدة

ذلك يعتمد على المكتبة، وكيف كنت منظمها. تذكر أن الملفات الرأسية للمكتبة، والقطات التي توجد فيها ملف الرأس، جزء أساسي من API للمكتبة. لذلك، إذا كنت تقود عملائك إلى اختيارهم بعناية واختيار من بين رؤوسك، فستحتاج إلى دعم هذا التخطيط لفترة طويلة. من الشائع إلى حد ما بالنسبة للمكتبات لتصدير واجهةهم بأكملها عبر ملف واحد، أو مجرد عدد قليل من الملفات، إذا كان جزءا من API اختياري حقا وكبير.

يجب أن يكون الاعتبار وقت التجميع: إذا كان لدى العميل تضمين اثنين عشر من الملفات لاستخدام مكتبتك، وتشمل تلك التي تتضمن داخليا، فيمكنها زيادة وقت التجميع بشكل كبير في مشروع كبير، إذا استخدمت في كثير من الأحيان. إذا ذهبت إلى هذا الطريق، فتأكد من أن كل ما تبذلونه من الأساس يحتوي على حراس مناسبة حول محتويات الملفات فقط، ولكن الخط بما في ذلك أيضا. على الرغم من ملاحظة: تقوم دول مجلس التعاون الخليجي الحديث بعمل جيد للغاية في هذه المشكلة بالذات ويتطلب فقط الحراس حول محتويات الرأس.

فيما يتعلق بانتفاخ البرنامج المترجم النهائي، فإنه يعتمد على سلسلة الأداة الخاصة بك، وكيف تجميع المكتبة، وليس كيف تضمن عميل المكتبات ملفات الرأس. (مع تحذير أنه إذا قمت بإعلان كائنات بيانات ثابتة في الرؤوس، فسوف ينتهي بعض الأنظمة بالربط في الكائنات التي تحدد البيانات هذه، حتى لو كان العميل لا يستخدمه.)

باختصار، ما لم تكن مكتبة كبيرة جدا، أو سلسلة أداة قديمة من الغراب جدا، أميل إلى الذهاب مع الواحدة. بالنسبة لي، تجميد قسم التنفيذ الحالي الخاص بك إلى رؤوس في واجهة برمجة تطبيقات المكتبة أكبر قلق أكبر من الآخرين.

المشكلة مع رؤوس الملفات الفردية هي شرح بالتفصيل من قبل الدكتور دوبس, ، كاتب مترجم الخبير. لا تستخدم أبدا رأس ملف واحد !!! في كل مرة يتم فيها تضمين رأس في ملف .cc / .cpp، يجب إعادة ترجمة لأنه يمكنك إطعام وحدات ماكرو الملفات لتغيير الرأس المترجم. لهذا السبب، فإن ملف رأس واحد سوف يزيد بشكل كبير من وقت الترجمة دون توفير أي بنفيت. مع C ++، يجب عليك تحسينه للمرة البشرية أولا، وتجميع الوقت هو الوقت البشري. يجب ألا تكون أبدا، لأنه يزيد بشكل كبير من وقت الترجمة، قم بتضمين أكثر مما تحتاج إلى تجميعه في أي رأس، يجب أن يكون لكل وحدة ترجمة (TU) ملف تنفيذها الخاص (.cc / .cpp)، وكل تو اسمه مع أسماء الملفات الفريدة؛ وبعد

في عقدي من تجربة تطوير C ++ SDK، أنا دينيا دائما لديك ثلاثة ملفات في كل وحدة. انا املك config.h التي يتم تضمينها تقريبيا كل ملف رأس يحتوي على PREREQS للحصول على الوحدة النمطية بأكملها مثل Platform-Config و stdint.h أمور. لدي أيضا global.h ملف يتضمن كل ملفات الرأس في الوحدة النمطية؛ هذا واحد في الغالب لتصحيح الأخطاء (ملحوظة تعداد طبقاتك في global.h ملف للحصول على أفضل اختبار وأسهل في تصحيح التعليمات البرمجية). القطعة المفقودة الرئيسية هنا هي أن ou يجب أن يكون لديك حقا public.h الملف الذي يشمل فقط واجهة برمجة التطبيقات العامة الخاصة بك.

في المكتبات التي يتم برمجةها بشكل سيئ، مثل دفعة وأسماء فئة Lower_Snake_SCASCE الخاصة بهم البشعة، فإنها تستخدم هذه الممارسة الأسوأ نصف المخبوزة باستخدام A detail (في بعض الأحيان باسم "آل") نمط تصميم المجلد إلى "إخفاء" واجهاتهم الخاصة. هناك خلفية طويلة وراء لماذا هذه هي أسوأ الممارسات، ولكن القصة القصيرة هي أنها تخلق مجنون كمية الكتابة الزائدة التي تحول بطانات واحدة إلى بطانات متعددة، وهي ليست متوافقة مع UML وتفسد مخطط التبعية UML مما يؤدي إلى أن أنماط رمز معقدة للغاية وأنماط تصميم غير متناسقة مثل الأطفال في الواقع الآباء والأمهات والعكس. أنت لا تريد أو تحتاج detail مجلد، تحتاج إلى استخدام public.h رأس مع مجموعة من وحدات الأخوة بدون أعاسب إضافية. حيث الخاص بك detail هو الأخوة وليس الطفل الموجود في reatliy أحد الوالدين. من المفترض أن تكون أسماء الأسماء لشيء واحد فقط وشيء واحد فقط: واجهة التعليمات البرمجية الخاصة بك مع رمز أشخاص آخرين، ولكن إذا كنت تحكم التعليمات البرمجية الخاصة بك، فعليك استخدام أسماء فئة و Funciton الفريدة لأنها ممارسات سيئة لاستخدام Nummapce عندما لا تفعل يجب أن تتسبب ذلك لأنه قد يتسبب في اصطدام جدول التجزئة الذي يتعرض بطء عملية تجميع. UML هو أفضل براتيس، لذلك إذا استطعت تنظيم رؤوسك، فهناك UML متوافق مع الكود الخاص بك هو التعريف أكثر قوة ومحمولة. أ public.h الملف هو كل ما تحتاجه لفضح فقط API العام؛ شكرا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top