2009-01-17 3 views
54

में हेडर फ़ाइलों में फ़ंक्शन परिभाषा लिखना मेरे पास एक कक्षा है जिसमें कई छोटे कार्य हैं। छोटे कार्यों से, मेरा मतलब है कि कोई भी प्रसंस्करण नहीं करता है लेकिन केवल एक शाब्दिक मूल्य लौटाता है। कुछ ऐसा:सी ++

string Foo::method() const{ 
    return "A"; 
} 

मैंने एक हेडर फ़ाइल "Foo.h" और स्रोत फ़ाइल "Foo.cpp" बनाई है। लेकिन चूंकि फ़ंक्शन बहुत छोटा है, इसलिए मैं इसे हेडर फ़ाइल में डालने के बारे में सोच रहा हूं। मेरे पास निम्नलिखित प्रश्न हैं:

  1. क्या कोई प्रदर्शन या अन्य समस्याएं हैं यदि मैं हेडर फ़ाइल में इन फ़ंक्शन परिभाषा को रखता हूं? मेरे पास इस तरह के कई कार्य होंगे।
  2. मेरी समझ तब होती है जब संकलन किया जाता है, संकलक हेडर फ़ाइल का विस्तार करेगा और इसे कहां रखा जाएगा। क्या वो सही है?

उत्तर

61

समारोह छोटी है, तो (मौका आप बदल जाएगा यह अक्सर कम है), और समारोह हेडर में अन्य हेडर संयुक्त असंख्य सहित (क्योंकि आपके समारोह उन पर निर्भर करता है) के बिना रखा जा सकता है, तो यह ऐसा करने के लिए पूरी तरह से मान्य है।

headera.h: आप उन्हें निर्वासन इनलाइन की घोषणा करते हैं, तो संकलक यह हर संकलन इकाई के लिए एक ही पते देने के लिए आवश्यक है

inline string method() { 
    return something; 
} 

सदस्य कार्यों निहित इनलाइन प्रदान की जाती हैं वे अंदर परिभाषित कर रहे हैं उनकी कक्षा उनके लिए वही सामान सच है: यदि उन्हें परेशानी के बिना हेडर में रखा जा सकता है, तो आप वास्तव में ऐसा कर सकते हैं।

क्योंकि फ़ंक्शन का कोड शीर्षलेख में दिखाई देता है और दृश्यमान होता है, तो कंपाइलर कॉल को इनलाइन करने में सक्षम होता है, यानी कॉल साइट पर सीधे फ़ंक्शन का कोड डालना (इतना नहीं कि आप पहले इनलाइन डालते हैं यह, लेकिन अधिक क्योंकि संकलक इस तरह से निर्णय लेता है, हालांकि, इनलाइन को केवल उस के बारे में संकलक के लिए एक संकेत है)। इसके परिणामस्वरूप प्रदर्शन सुधार हो सकता है, क्योंकि संकलक अब देखता है कि तर्क फ़ंक्शन के लिए स्थानीय चर से मेल खाता है, और जहां तर्क एक-दूसरे को उपनाम नहीं करता है - और अंतिम लेकिन कम से कम नहीं, फ़ंक्शन फ़्रेम आवंटन की आवश्यकता नहीं है।

मेरी समझ तब होती है जब संकलन किया जाता है, संकलक हेडर फ़ाइल का विस्तार करेगा और इसे कहां शामिल किया जाएगा। क्या वो सही है?

हाँ, यह सही है।फ़ंक्शन को प्रत्येक स्थान पर परिभाषित किया जाएगा जहां आप अपना हेडर शामिल करते हैं। कंपाइलर दूसरों को खत्म करके परिणामस्वरूप प्रोग्राम में केवल एक उदाहरण डालने की परवाह करेगा।

+0

धन्यवाद। ये सभी छोटे कार्य वर्चुअल हैं। क्या इससे इनलाइनिंग में कोई फर्क पड़ता है? और मुझे लगता है कि स्रोत फ़ाइल में फ़ंक्शन बॉडी लिखना और इनलाइन के रूप में चिह्नित करना सीधे शीर्षलेख में लिखने से बेहतर है। मुझे डर है, अगर इन सभी कार्यों को परिभाषित किया गया है तो हेडर फ़ाइल कम पठनीय होगी। –

+0

यदि संकलक वर्चुअल फ़ंक्शन कॉल की दिशा का पता लगा सकता है, तो यह भी इनलाइन कर सकता है: b * b_ = new d; छदाम (b_); // अगर यह initines inlines, यह देखेंगे कि बी_ डी है। तो यह वर्चुअल फ़ंक्शन परिभाषा के कोड को रेखांकित कर सकता है क्योंकि यह डी में है। वर्चुअल इसे और अधिक कठिन बनाता है, लेकिन असंभव नहीं –

+0

लेकिन मैं आपसे सहमत हूं: मैं कोड को हेडर में डालने में अक्सर रूचि रखता हूं, क्योंकि जब मैं इसे बदलता हूं, तो यह इसे नियंत्रित करने वाले सभी कोड को प्रभावित करता है, और अक्सर हेडर में परिभाषित करने की आवश्यकता होती है कोड कम से कम एक अन्य शीर्षलेख पर निर्भर करता है। (हमेशा आसान नहीं है। सरल गेटर्स के लिए, मैंने उन्हें वहां रखा)। –

4

प्रदर्शन में वृद्धि होगी क्योंकि शीर्षलेख फ़ाइलों में कार्यान्वयन को स्पष्ट रूप से रेखांकित किया गया है। जैसा कि आपने बताया है कि आपके कार्य छोटे हैं, इनलाइन ऑपरेशन आपके लिए IMHO के लिए बहुत फायदेमंद होगा।

आप संकलक बारे में क्या कहना true.There संकलक — हेडर फाइल या .cpp फ़ाइल में कोड के बीच — इनलाइन करने के अलावा अन्य के लिए कोई अंतर नहीं है भी है।

2
  1. अपने कार्यों कि सरल कर रहे हैं, उन्हें इनलाइन बनाने, और आप उन्हें हेडर फाइल में वैसे भी रहना होगा। इसके अलावा, किसी भी सम्मेलन सिर्फ यही है - सम्मेलन।

  2. हां, कंपाइलर हेडर फ़ाइल का विस्तार करता है जहां यह # अंतर्निहित बयान का सामना करता है।

1

यह कोडिंग मानकों है कि आपके मामले में लागू होते हैं, लेकिन पर निर्भर करता है: लूप और कुछ और बिना

छोटे कार्यों बेहतर प्रदर्शन के लिए inlined जाना चाहिए (लेकिन थोड़ा बड़ा कोड - कुछ विवश या एम्बेडेड अनुप्रयोगों के लिए महत्वपूर्ण)।

यदि आपके पास हेडर में फ़ंक्शन का बॉडी है तो आपके पास डिफ़ॉल्ट इनलाइन (डी) (जो गति की बात आती है) में एक अच्छी बात होगी।

कंपेलर द्वारा ऑब्जेक्ट फ़ाइल बनाई जाने से पहले प्रीप्रोसेसर को (जीसीसी के लिए -ई विकल्प) कहा जाता है और परिणाम संकलक को भेजा जाता है जो ऑब्जेक्ट को कोड से बाहर बनाता है।

तो कम जवाब है:

- हेडर में कार्यों की घोषणा अच्छा है (लेकिन अंतरिक्ष के लिए नहीं) गति के लिए -

1

आप इनलाइन कार्यों का उपयोग करना चाहिए। बेहतर समझ और ट्रेडऑफ शामिल होने के लिए यह Inline Functions पढ़ें।

+0

लिंक अब मान्य नहीं है –

+0

यह वास्तव में प्रश्न पर तुरंत लागू नहीं होता है, सवाल यह नहीं है कि "मैं प्रदर्शन में सुधार कैसे करूं?" या ऐसा यह कहना उचित होगा कि इसे "इनलाइन फ़ंक्शन" कहा जाता है और इस तरह की विधियों को समझाते हुए एक लिंक देने के लिए कहा जाता है। – Kit10

12

अपने संकलक पर निर्भर करता है और यह सेटिंग यह निम्न कोई भी कार्य कर सकते हैं क्या है:

  • यह इनलाइन कीवर्ड अनदेखा कर सकते हैं (यह संकलक, नहीं एक आदेश को सिर्फ एक संकेत है) और उत्पन्न स्टैंड -अलोन फ़ंक्शंस। यह ऐसा कर सकता है यदि आपका फ़ंक्शन एक कंपाइलर-निर्भर जटिलता दहलीज से अधिक हो। जैसे बहुत सारे नेस्टेड लूप।
  • यह आपके स्टैंड-अलोन फ़ंक्शन की तुलना में तय हो सकता है इनलाइन विस्तार के लिए एक अच्छा उम्मीदवार है।

कई मामलों में, संकलक यह निर्धारित करने के लिए एक बेहतर स्थिति में है कि कोई फ़ंक्शन आपके से रेखांकित किया जाना चाहिए, इसलिए दूसरे अनुमान लगाने में कोई बात नहीं है। मुझे अंतर्निहित इनलाइनिंग का उपयोग करना पसंद है जब किसी वर्ग के पास केवल छोटे कार्य होते हैं क्योंकि कक्षा में वहां कार्यान्वयन करना सुविधाजनक होता है। यह बड़े कार्यों के लिए इतना अच्छा काम नहीं करता है।

दूसरी बात यह ध्यान में रखना है कि यदि आप एक डीएलएल/साझा लाइब्रेरी में कक्षा निर्यात कर रहे हैं (आईएमएचओ का अच्छा विचार नहीं है, लेकिन लोग इसे वैसे भी करते हैं) तो आपको इनलाइन फ़ंक्शंस के साथ वास्तव में सावधान रहना होगा। संकलक कि DLL बनाया का फैसला करता है एक समारोह inlined जाना चाहिए, तो आप संभावित समस्याओं के एक जोड़े हैं:

  1. संकलक कार्यक्रम DLL का उपयोग कर तय कर सकते हैं का निर्माण करने के लिए नहीं समारोह इतना इनलाइन यह एक उत्पन्न होगा फ़ंक्शन का संदर्भ संदर्भ जो मौजूद नहीं है और DLL लोड नहीं होगा।
  2. आप DLL को अद्यतन करने और inlined समारोह, क्लाइंट प्रोग्राम अभी भी समारोह के बाद से है कि समारोह के पुराने संस्करण का उपयोग किया जाएगा बदलते हैं तो ग्राहक कोड में inlined गया।
+0

अच्छा जवाब। धन्यवाद :) बीटीडब्ल्यू, मेरे कार्य आभासी हैं और जब यह इनलाइन करते हैं तो इससे कोई फर्क पड़ता है? –

+2

वर्चुअल फ़ंक्शंस को रेखांकित नहीं किया जा सकता है, उन्हें vtable में पॉइंटर के माध्यम से संदर्भित करने की आवश्यकता है। मैंने कभी कोशिश नहीं की, लेकिन संकलक को या तो इनलाइन को अनदेखा करना चाहिए या इसके बारे में शिकायत करना चाहिए। – Ferruccio

+1

यदि संकलन समय पर प्रकार ज्ञात है तो वर्चुअल फ़ंक्शंस को रेखांकित किया जा सकता है। यह अभ्यास में बहुत दुर्लभ है। – Tom

1

सी ++ शिकायत नहीं करेगा अगर आप करते हैं, लेकिन आमतौर पर बोलते हैं, आपको नहीं करना चाहिए।

जब आप फ़ाइल को शामिल करते हैं, तो शामिल फ़ाइल की पूरी सामग्री शामिल करने के बिंदु पर डाली जाती है। इसका अर्थ यह है कि आपके हेडर में आपके द्वारा डाली गई किसी भी परिभाषा को उस फ़ाइल में कॉपी किया जाता है जिसमें हेडर शामिल होता है।

छोटी परियोजनाओं के लिए, यह एक मुद्दा होने की संभावना नहीं है। लेकिन बड़ी परियोजनाओं के लिए, यह चीजों को संकलित करने में अधिक समय ले सकता है (जैसा कि हर बार सामना किया जाता है उसी कोड को फिर से संकलित किया जाता है) और आपके निष्पादन योग्य आकार को काफी हद तक फहरा सकता है। यदि आप किसी कोड फ़ाइल में परिभाषा में परिवर्तन करते हैं, तो केवल उस .cpp फ़ाइल को पुनः संयोजित करने की आवश्यकता है। यदि आप हेडर फ़ाइल में किसी परिभाषा में परिवर्तन करते हैं, तो प्रत्येक कोड फ़ाइल जिसमें हेडर शामिल है, को पुन: संकलित करने की आवश्यकता है। एक छोटा बदलाव आपको अपनी पूरी परियोजना को फिर से कंपाइल कर सकता है!

कभी-कभी अपवादों को छोटे कार्यों के लिए बनाया जाता है जो बदलने की संभावना नहीं होती है (उदाहरण के लिए फ़ंक्शन परिभाषा एक पंक्ति है)।