बिल्कुल। सी/सी ++ बिल्ड मॉडल है ... अहम ... एक अनाचारवाद (सर्वश्रेष्ठ कहने के लिए)। बड़ी परियोजनाओं के लिए यह एक गंभीर पिटा बन जाता है।
जैसा कि नील सही तरीके से नोट करता है, यह आपके वर्ग डिज़ाइन के लिए डिफ़ॉल्ट दृष्टिकोण नहीं होना चाहिए, जब तक आपको वास्तव में आवश्यकता न हो, तब तक अपने रास्ते से बाहर न जाएं।
ब्रेकिंग परिपत्र में संदर्भ शामिल हैं एक कारण है जहां आपको आगे की घोषणाओं का उपयोग करना होगा।
// a.h
#include "b.h"
struct A { B * a; }
// b.h
#include "a.h" // circlular include reference
struct B { A * a; }
// Solution: break circular reference by forward delcaration of B or A
समय के पुनर्निर्माण को कम करना - निम्नलिखित कोड
// foo.h
#include <qslider>
class Foo
{
QSlider * someSlider;
}
अब हर .cpp फ़ाइल है कि प्रत्यक्ष या परोक्ष रूप Foo.h में खींचती भी QSlider.h और उसके निर्भरता के सभी में खींचती है कल्पना कीजिए। यह सैकड़ों .cpp फाइलें हो सकती है!(प्रीकंपिल्ड हेडर थोड़ा सा मदद करते हैं - और कभी-कभी बहुत कुछ - लेकिन वे स्मृति/डिस्क दबाव में डिस्क/सीपीयू दबाव को बदलते हैं, और इस प्रकार जल्द ही "अगली" सीमा को मार रहे हैं)
यदि शीर्षलेख को केवल एक संदर्भ घोषणा की आवश्यकता है, तो निर्भरता अक्सर कुछ फ़ाइलों तक सीमित हो सकती है, उदाहरण के लिए foo.cpp।
वृद्धिशील निर्माण समय को कम करना - प्रभाव स्वयं को (स्थिर पुस्तकालय की बजाय) शीर्षकों से निपटने पर भी अधिक स्पष्ट है। कल्पना कीजिए कि आप
// bar.h
#include "foo.h"
class Bar
{
Foo * kungFoo;
// ...
}
अब अगर आपके सीपीपी की जरूरत के सबसे bar.h में खींचने के लिए, वे भी परोक्ष रूप से foo.h. में खींच इस प्रकार, foo.h ट्रिगर्स के प्रत्येक परिवर्तन इन सभी .cpp फ़ाइलों का निर्माण (जो फू को जानने की भी आवश्यकता नहीं है!)। bar.h बजाय फू के लिए एक आगे घोषणा उपयोग करता है, foo.h पर निर्भरता bar.cpp तक ही सीमित है:
// bar.h
class Foo;
class Bar
{
Foo * kungFoo;
// ...
}
// bar.cpp
#include "bar.h"
#include "foo.h"
// ...
यह इतना आम है कि यह एक पैटर्न है - PIMPL pattern। इसका उपयोग दो गुना है: पहला यह सच इंटरफेस/कार्यान्वयन अलगाव प्रदान करता है, दूसरा निर्माण निर्भरताओं को कम कर रहा है। प्रैक्टिस में, मैं उनकी उपयोगीता 50:50 वजन कम करूंगा।
आपको हेडर में संदर्भ की आवश्यकता है, तो आप निर्भर प्रकार का प्रत्यक्ष तत्काल नहीं हो सकते हैं। यह उन मामलों को सीमित करता है जहां आगे की घोषणाओं को लागू किया जा सकता है। यदि आप इसे स्पष्ट रूप से करते हैं, तो इसके लिए उपयोगिता वर्ग (जैसे boost::scoped_ptr) का उपयोग करना आम है।
क्या बिल्ड समय इसके लायक है?Definitely, मैं कहूंगा। सबसे खराब मामले में निर्माण समय परियोजना में फाइलों की संख्या के साथ बहुपद बढ़ता है। अन्य तकनीकें - जैसे तेज मशीनें और समांतर बिल्ड - केवल प्रतिशत लाभ प्रदान कर सकती हैं।
तेजी से निर्माण, अधिकतर डेवलपर्स परीक्षण करते हैं कि उन्होंने क्या किया है, अधिकतर यूनिट परीक्षण चलते हैं, तेजी से निर्माण ब्रेक तय किए जा सकते हैं, और कम डेवलपर्स को समाप्त होने का अंत होता है।
प्रैक्टिस में, अपने निर्माण समय को प्रबंधित करना, जबकि एक बड़ी परियोजना (सैकड़ों स्रोत फाइलें) पर आवश्यक है, यह अभी भी छोटी परियोजनाओं पर "आराम अंतर" बनाता है। इसके अलावा, तथ्य के बाद सुधार जोड़ना अक्सर धैर्य में व्यायाम होता है, क्योंकि एक फिक्स 40 मिनट के निर्माण के केवल सेकंड (या कम) को बंद कर सकता है।
यदि बिल्डिंग समय के बारे में आपने जो कहा है, वह विस्तारित रूप से बढ़ रहा है, जिस परियोजना पर मैं काम कर रहा हूं (जिसमें 100 स्रोत फाइलें हैं) को स्क्रैच से संकलित करने के लिए लगभग 2^100 सेकंड लेना चाहिए - इसके बजाय इसमें लगभग एक मिनट लगते हैं। –
@Neil: आपके द्वारा जोड़े जाने वाली प्रत्येक फ़ाइल के लिए, बिल्ड समय परियोजना के आकार के अनुपात में बढ़ता है (क्योंकि नई फ़ाइल को संकलित करने के लिए, आपको प्रोजेक्ट के आकार के आनुपातिक कुछ शीर्षकों को संसाधित करना होगा)। यह मेरे लिए घातीय लगता है। –
स्पष्ट किया गया है: यह निश्चित रूप से सबसे खराब स्थिति परिदृश्य (कोड-गहन, दृढ़ता से परस्पर निर्भर हेडर) है। मेरे अनुभव में, मशीन की ईप्रोफॉर्मेंस सीमाओं को मारने के बाद स्पीड सर्पिल बनाएं, और आप जो कुछ भी कर सकते हैं वह बाधाओं के बीच व्यापार कर रहा है। --- मुझे उम्मीद है कि "निष्क्रिय उपेक्षा" आम तौर पर (केवल) बहुपद बढ़ने का कारण बनती है, लेकिन गलत उम्मीदें या अनुपयुक्त कोडिंग मानकों से आप एक्सपोनियल ड्रेनहोल का नेतृत्व कर सकते हैं। – peterchen