c++ - फ़ंक्शन पैरामीटर के लिए 'const' का उपयोग करें


const साथ आप कितनी दूर जाते हैं? क्या आप आवश्यकतानुसार फ़ंक्शन const करते हैं या क्या आप पूरे हॉग में जाते हैं और हर जगह इसका उपयोग करते हैं? उदाहरण के लिए, एक सरल म्यूटेटर की कल्पना करें जो एक बुलियन पैरामीटर लेता है:

void SetValue(const bool b) { my_val_ = b; }

क्या यह वास्तव में उपयोगी है? निजी तौर पर मैं पैरामीटर सहित बड़े पैमाने पर इसका उपयोग करने का विकल्प चुनता हूं, लेकिन इस मामले में मुझे आश्चर्य है कि क्या यह सही है?

मुझे यह भी जानने से हैरान था कि आप फ़ंक्शन घोषणा में मापदंडों से const कर सकते हैं लेकिन फ़ंक्शन परिभाषा में इसे शामिल कर सकते हैं, उदाहरण के लिए:

.h फ़ाइल

void func(int n, long l);

.cpp फ़ाइल

void func(const int n, const long l)

क्या इसका कोई कारण है? यह मुझे थोड़ा असामान्य लगता है



Answers



कारण यह है कि पैरामीटर के लिए const केवल फ़ंक्शन के भीतर स्थानीय रूप से लागू होता है, क्योंकि यह डेटा की प्रतिलिपि पर काम कर रहा है। इसका मतलब है कि फ़ंक्शन हस्ताक्षर वास्तव में वैसे भी वही है। हालांकि ऐसा करने के लिए संभवतः खराब शैली है

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




"कोंट निरर्थक है जब तर्क मूल्य से पारित हो जाता है, क्योंकि आप कॉलर की ऑब्जेक्ट को संशोधित नहीं करेंगे।"

गलत।

यह आपके कोड और अपने मान्यताओं के आत्म-दस्तावेजीकरण के बारे में है

यदि आपके कोड में कई लोग काम कर रहे हैं और आपके फ़ंक्शन अ-तुच्छ हैं तो आपको "कॉन्स्ट" को किसी भी चीज और सभी चीजों को चिह्नित करना चाहिए जो आप कर सकते हैं। औद्योगिक-शक्ति कोड लिखते समय, आपको हमेशा यह मानना ​​चाहिए कि आपके सहकर्मियों आप को किसी भी तरह से प्राप्त करने की कोशिश कर रहे मनोवैज्ञानिक हैं (खासकर जब वह भविष्य में अक्सर होता है)

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




कभी-कभी (बहुत बार!) मुझे किसी और के सी ++ कोड को अनसुना करना पड़ता है और हम सभी जानते हैं कि किसी और की सी ++ कोड परिभाषा के द्वारा पूरी तरह से एक गड़बड़ है :) तो स्थानीय डेटा प्रवाह को समझने के लिए मैं जो भी चीज करता हूं, वह हर चर परिभाषा में एक जगह होती है, जब तक कम्पाइलर भौंकने शुरू नहीं करता है। इसका मतलब है कि कॉन्स्ट-क्वालीफाइंग वैल्यू आरजीएं भी हैं, क्योंकि वे कॉलर द्वारा शुरू किए गए सिर्फ फैंसी स्थानीय वैरिएबल हैं।

आह, मैं चाहता हूं कि वेरिएबल डिफ़ॉल्ट रूप से कॉन्स्ट हो गए थे और गैर-कॉन्स्ट चेंबल्स के लिए अस्थिर करने की आवश्यकता थी :)




निम्नलिखित दो पंक्तियां कार्यात्मक रूप से समतुल्य हैं:

int foo (int a);
int foo (const int a);

जाहिर है, आप इसे foo के शरीर में संशोधित नहीं कर पाएंगे यदि यह दूसरी तरह से परिभाषित हो, लेकिन बाहर से कोई अंतर नहीं है

जहां const वास्तव में काम में आता है संदर्भ या सूचक पैरामीटर के साथ:

int foo (const BigStruct &a);
int foo (const BigStruct *a);

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

*: जब तक कि वह कंटैस-नास को दूर नहीं करता है, लेकिन यह एक और पोस्ट है




अतिरिक्त अतिसंवेदनशील कॉन्स्ट एपीआई स्टैंडपॉइंट से खराब है:

कॉलर या एपीआई उपयोगकर्ता (यह केवल कार्यान्वयन को बाधित) के लिए कोई सार्थक वादा नहीं बनाते हुए, आपके एपीआई के द्वारा मूल्य के थक्के अपने एपीआई के द्वारा पारित आंतरिक प्रकार के मानकों के लिए अपने कोड में अतिरिक्त अतिसंवेदनशील संविधान लगा रहा है।

एपीआई में बहुत सारे 'कॉन्स्ट' की ज़रूरत नहीं होती है जैसे " रोलिंग भेड़िया ", अंततः लोग 'कॉन्स्ट' की अनदेखी करना शुरू कर देंगे क्योंकि यह सभी जगह पर है और इसका अधिकांश समय का मतलब नहीं है

एपीआई में अतिरिक्त कंस्ट्रक्शंस के लिए "रिडिटीओ एड बेकार" तर्क अच्छा होगा यदि पहले से ही दो अंक बेहतर होंगे, तो अधिक तर्क पैरामीटर अच्छे होंगे, तो प्रत्येक तर्क जो उस पर एक कन्स्ट्रक्शन हो सकता है, उस पर एक कन्स्ट्रक्शन होना चाहिए। असल में, अगर यह वास्तव में अच्छा था, तो आप चाहते हैं कि पैरा को पैरामीटर के लिए डिफॉल्ट हो और आप "पैराटेक्शर" को बदलना चाहते हैं, जैसे कि "म्यूटिव" जैसे एक कीवर्ड।

तो हम ऐसा कर सकते हैं जब तक हम इसे कर सकते हैं:

void mungerum(char * buffer, const char * mask, int count);

void mungerum(char * const buffer, const char * const mask, const int count);

ऊपर दिए गए कोड की रेखा पर विचार करें केवल घोषणा ही नहीं है और अधिक बरबाद हो और अब और पढ़ने में कठिन हो लेकिन एपीआई प्रयोक्ता द्वारा चार 'कॉन्स्ट' कीवर्ड में से तीन को सुरक्षित रूप से नजरअंदाज किया जा सकता है। हालांकि, 'const' के अतिरिक्त उपयोग ने दूसरी पंक्ति को संभावित खतरनाक बना दिया है !

क्यूं कर?

पहला पैरामीटर char * const buffer का त्वरित गलत char * const buffer आपको लगता है कि यह उस डेटा बफर में मेमोरी को संशोधित नहीं करेगा जो कि पारित किया गया है - हालांकि, यह सच नहीं है! ज़ोरदार 'const' स्कैन या जल्दी से गलत तरीके से पढ़ने के दौरान आपके एपीआई के बारे में खतरनाक और ग़लत मान्यताओं का कारण बन सकता है

अत्यधिक कार्यात्मक एक कोड क्रियान्वयन स्टैंड-पॉइंट से भी खराब हैं:

#if FLEXIBLE_IMPLEMENTATION
       #define SUPERFLUOUS_CONST
#else
       #define SUPERFLUOUS_CONST             const
#endif

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count);

यदि FLEXIBLE_IMPLEMENTATION सच नहीं है, तो एपीआई "वादा" है, इस कार्य को कार्यान्वित करने के लिए नहीं, नीचे पहला तरीका।

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       // Will break if !FLEXIBLE_IMPLEMENTATION
       while(count--)
       {
              *dest++=*source++;
       }
}

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       for(int i=0;i<count;i++)
       {
              dest[i]=source[i];
       }
}

यह बनाने के लिए एक बहुत मूर्ख वादा है आपको एक ऐसा वादा क्यों करना चाहिए जिससे आपके कॉलर पर कोई लाभ न मिले और केवल आपके कार्यान्वयन को सीमित कर दिया जाए?

हालांकि ये दोनों एक ही समारोह के पूरी तरह से वैध कार्यान्वयन हैं, हालांकि आपने जो कुछ किया है, वह अपनी पीठ के पीछे एक हाथ से बेकार है।

इसके अलावा, यह एक बहुत उथले वादा है जो आसानी से (और कानूनी रूप से निरोधक) है

inline void bytecopyWrapped(char * dest,
   const char *source, int count)
{
       while(count--)
       {
              *dest++=*source++;
       }
}
void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source,SUPERFLUOUS_CONST int count)
{
    bytecopyWrapped(dest, source, count);
}

देखो, मैंने इसे किसी भी तरह लागू किया है, हालांकि मैंने ऐसा न करने का वादा किया- सिर्फ आवरण समारोह का उपयोग करते हुए ऐसा तब होता है जब बुरे आदमी ने फिल्म में किसी को मारने का वादा नहीं किया और उसके गुर्गे का आदेश देने के बजाय उन्हें मार दिया।

उन अनावश्यक const की फिल्म खराब लड़के से एक वादा की तुलना में अधिक मूल्य नहीं है

लेकिन झूठ बोलने की क्षमता भी बदतर हो जाती है:

मुझे प्रबुद्ध कर दिया गया है कि आप नकली const का उपयोग करके शीर्षलेख (घोषणा) और कोड (परिभाषा) में कन्फन कर सकते हैं। कॉन्स्ट-खुश एडवोकेट्स का दावा है कि यह एक अच्छी बात है क्योंकि इससे आपको केवल परिभाषा में ही रखा जा सकता है।

// Example of const only in definition, not declaration
class foo { void test(int *pi); };
void foo::test(int * const pi) { }

हालांकि, बातचीत सच है ... आप केवल घोषणा में एक नकली कस्बे रख सकते हैं और परिभाषा में इसे अनदेखा कर सकते हैं यह केवल एपीआई में एक अतिसंवेदनशील कन्स्ट्रक्शन बनाता है और एक भयानक चीज़ और एक भयानक झूठ - यह उदाहरण देखें:

class foo
{
    void test(int * const pi);
};

void foo::test(int *pi) // Look, the const in the definition is so superfluous I can ignore it here
{
    pi++;  // I promised in my definition I wouldn't modify this
}

सभी अनावश्यक संविधान वास्तव में कार्यान्वयनकर्ता के कोड को किसी अन्य स्थानीय प्रति या एक आवरण समारोह का उपयोग करने के लिए मजबूर करते हुए कम पठनीय बनाते हैं जब वे वैरिएबल को बदलना चाहते हैं या फिर गैर-कॉन्स्ट संदर्भ द्वारा चर को पास करना चाहते हैं।

इस उदाहरण को देखें कौन सा पठनीय है? क्या यह स्पष्ट है कि दूसरे फ़ंक्शन में अतिरिक्त चर का एकमात्र कारण है क्योंकि कुछ एपीआई डिजाइनर ने एक अतिसंवेदनशील कंस्ट्रक्शन में फेंक दिया है?

struct llist
{
    llist * next;
};

void walkllist(llist *plist)
{
    llist *pnext;
    while(plist)
    {
        pnext=plist->next;
        walk(plist);
        plist=pnext;    // This line wouldn't compile if plist was const
    }
}

void walkllist(llist * SUPERFLUOUS_CONST plist)
{
    llist * pnotconst=plist;
    llist *pnext;
    while(pnotconst)
    {
        pnext=pnotconst->next;
        walk(pnotconst);
        pnotconst=pnext;
    }
}

उम्मीद है कि हम यहाँ कुछ सीखा है। अतिसंवेदनशील कन्स्ट्रक्शन एक एपीआई-अवरोधक आँखें, एक कष्टप्रद नाग, एक उथले और अर्थहीन वादा, एक अनावश्यक बाधा है, और कभी-कभी बहुत खतरनाक गलतियों की ओर जाता है




const को सी ++ में डिफ़ॉल्ट होना चाहिए इस कदर :

int i = 5 ; // i is a constant

var int i = 5 ; // i is a real variable



जब मैंने जीवित रहने के लिए सी ++ को कोडित किया तो मैं सबकुछ कर सकता हूं जो मैं कर सकता हूं। कंसीलेटर का उपयोग करने में आपकी सहायता करने के लिए const का उपयोग करना एक शानदार तरीका है उदाहरण के लिए, आपके विधि रिटर्न मान को कॉन्फ़िगर करना आपको टाइपो से बचा सकता है जैसे कि:

foo() = 42

जब आप मतलब:

foo() == 42

यदि गैर-कॉन्फेंट संदर्भ वापस करने के लिए foo () परिभाषित किया गया है:

int& foo() { /* ... */ }

कंपाइलर खुशी से आप फ़ंक्शन कॉल द्वारा दिए गए अज्ञात अस्थायी रूप से एक मान निर्दिष्ट करेंगे। इसे बनाना:

const int& foo() { /* ... */ }

इस संभावना को खत्म कर देता है




इस विषय पर पुराने "गुरु के सप्ताह में" आलेखों में comp.lang.c ++ पर यहां चर्चा की गई है

संबंधित GOTW लेख यहां हर्ब Sutter की वेब साइट पर उपलब्ध है




मैं फ़ंक्शन पैरामीटर पर कॉन्स्ट का उपयोग करता हूं जो संदर्भ (या पॉइंटर्स) हैं जो केवल [डेटा] में हैं और फ़ंक्शन द्वारा संशोधित नहीं किए जाएंगे। अर्थ, जब एक संदर्भ का उपयोग करने का उद्देश्य डेटा को कॉपी करने से बचने और पारित पैरामीटर को बदलने की अनुमति नहीं देना है।

आपके उदाहरण में बूलीयन बी पैरामीटर को लगाकर केवल कार्यान्वयन पर एक बाधा डालता है और क्लास के इंटरफ़ेस में योगदान नहीं देता (हालांकि, पैरामीटर को बदलना आम तौर पर नहीं किया जाता है)।

के लिए फ़ंक्शन हस्ताक्षर

void foo(int a);

तथा

void foo(const int a);

एक ही है, जो आपके। सी और। एच बताता है

आसफ




मैं कहता हूं कि आपका मूल्य पैरामीटर

इस छोटी गाड़ी समारोह पर विचार करें:

bool isZero(int number)
{
  if (number = 0)  // whoops, should be number == 0
    return true;
  else
    return false;
}

अगर संख्या पैरामीटर const था, तो कंपाइलर बंद हो जाएगा और हमें बग की चेतावनी देगा।




यदि आप ->* या .* ऑपरेटर्स का उपयोग करते हैं, तो यह आवश्यक है

यह आपको कुछ लिखने से रोकता है

void foo(Bar *p) { if (++p->*member > 0) { ... } }

जो मैंने लगभग अभी किया था, और शायद जो आपके इरादा नहीं करता है

मैं क्या कहना चाहता था वह था

void foo(Bar *p) { if (++(p->*member) > 0) { ... } }

और अगर मैं Bar * और p बीच एक const डाल दिया था, तो संकलक ने मुझे बताया होगा कि




आह, एक कड़ी मेहनत एक तरफ, एक घोषणा एक अनुबंध है और यह वास्तव में मान से एक तर्क तर्क पारित करने का मतलब नहीं है। दूसरी तरफ, यदि आप फ़ंक्शन कार्यान्वयन को देखते हैं, तो आप संकलक को अधिक अनुकूलन देते हैं यदि आप एक तर्क निरंतर घोषित करते हैं




const अजीब है जब तर्क मूल्य से पारित होता है, क्योंकि आप कॉलर की ऑब्जेक्ट को संशोधित नहीं करेंगे।

संदर्भ से गुजरते समय const को प्राथमिकता दी जानी चाहिए, जब तक कि फ़ंक्शन का उद्देश्य पारित मूल्य को संशोधित करना न हो।

अंत में, एक फ़ंक्शन जो वर्तमान ऑब्जेक्ट को संशोधित नहीं करता है (यह), और संभवतः कॉन्स्ट को घोषित किया जाना चाहिए एक उदाहरण नीचे है:

int SomeClass::GetValue() const {return m_internalValue;}

यह उस वस्तु को संशोधित न करने का वादा है जिसमें यह कॉल लागू किया गया है। दूसरे शब्दों में, आप कॉल कर सकते हैं:

const SomeClass* pSomeClass;
pSomeClass->GetValue();

यदि फ़ंक्शन कंसल्ट नहीं था, तो इसका परिणाम एक कंपाइलर चेतावनी होगा।




मूल्य मानकों को चिह्नित 'const' निश्चित रूप से एक व्यक्तिपरक बात है

हालांकि मैं वास्तव में मान पैरामीटर const को चिह्नित करना पसंद करता हूं, जैसे आपके उदाहरण में।

void func(const int n, const long l) { /* ... */ }

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

एक संक्षिप्त समारोह के लिए, यह तर्क है कि 'const' के लिए समय / स्थान की बर्बादी है, क्योंकि यह आम तौर पर बहुत स्पष्ट है कि फ़ंक्शन द्वारा तर्कों को संशोधित नहीं किया जाता है।

हालांकि एक बड़े फ़ंक्शन के लिए, यह कार्यान्वयन दस्तावेज़ का एक रूप है, और इसे संकलक द्वारा लागू किया जाता है।

मुझे यकीन है कि अगर मैं 'एन' और 'एल' के साथ कुछ गणना करता हूं, तो मैं उस गणना को अलग-अलग परिणाम देने के डर के बिना उस स्थानांतरित कर सकता / सकती हूं क्योंकि मुझे ऐसा स्थान नहीं मिला जहां एक या दोनों बदल गए हैं

चूंकि यह एक कार्यान्वयन विवरण है, इसलिए आपको हेडर में मान पैरामीटर को घोषित करने की आवश्यकता नहीं है, जैसे कि कार्यान्वयन के उपयोग के समान नामों से फ़ंक्शन पैरामीटर को घोषित करने की आवश्यकता नहीं है।




यदि आप इसका उल्लेख करते हैं, तो यह आपके एपीआई के कॉल करने वालों को प्रभावित नहीं करता है, यही कारण है कि यह सामान्यतः नहीं किया जाता है (और हैडर में आवश्यक नहीं है)। यह केवल आपके फ़ंक्शन के कार्यान्वयन को प्रभावित करता है।

यह विशेष रूप से करने के लिए एक बुरी बात नहीं है, लेकिन लाभ यह महान नहीं है कि यह आपके एपीआई को प्रभावित नहीं करता है, और यह टाइपिंग जोड़ता है, इसलिए यह आम तौर पर नहीं किया जाता है।




मैं value-passed parametere के लिए const का उपयोग नहीं करता कॉल करने वाले को परवाह नहीं है कि आप पैरामीटर को संशोधित करते हैं या नहीं, यह कार्यान्वयन विवरण है।

क्या वास्तव में महत्वपूर्ण है कि वे अपने उदाहरण को संशोधित न करने के तरीकों के रूप में चिह्नित करें। जैसे ही आप जाते हैं, क्योंकि अन्यथा आप या तो const_cast के बहुत से <> समाप्त हो सकते हैं या आपको लगता है कि एक विधि const चिन्ह को बहुत सारे कोड बदलने की आवश्यकता होती है क्योंकि यह अन्य विधियों को कॉल करता है जिन्हें const को चिह्नित किया जाना चाहिए

अगर मैं उन्हें संशोधित करने की आवश्यकता नहीं है तो मैं स्थानीय वार्स कॉन्स्ट को भी चिह्नित करता हूं। मेरा मानना ​​है कि यह कोड को "चलती भागों" की पहचान करना आसान बनाकर समझने में आसान बनाता है




मैं जहां भी संभव हो वहां कॉन्स्ट्रक्ट का इस्तेमाल करते हैं। (या लक्षित भाषा के लिए अन्य उपयुक्त कीवर्ड।) मैं इसे पूरी तरह से करता हूं क्योंकि इससे कंपाइलर को अतिरिक्त अनुकूलन करने की अनुमति मिलती है जो कि वह अन्यथा नहीं कर पाएगी। चूंकि मुझे पता नहीं है कि यह अनुकूलन क्या हो सकता है, मैं हमेशा ऐसा करता हूं, जहां भी यह मूर्खतापूर्ण लगता है।

मैं जानता हूँ कि सभी के लिए, कंपाइलर एक const मूल्य पैरामीटर को बहुत अच्छी तरह से देख सकता है, और कहते हैं, "अरे, यह फ़ंक्शन किसी भी तरह से इसे संशोधित नहीं कर रहा है, इसलिए मैं संदर्भ से पास कर सकता हूं और कुछ घड़ी चक्रों को बचा सकता हूं।" मुझे नहीं लगता कि यह कभी ऐसा काम करेगा, क्योंकि यह फ़ंक्शन हस्ताक्षर बदलता है, लेकिन यह बिंदु बना देता है शायद यह कुछ अलग ढेर हेरफेर या कुछ और करता है ... मुद्दा यह है, मुझे नहीं पता, लेकिन मुझे पता है कि कंपाइलर से चालाक होने की कोशिश करने से मुझे केवल शर्मिंदा होने की ओर जाता है

सी ++ के पास कुछ अतिरिक्त सामान हैं, जिसमें संकलन-योग्यता के विचार होते हैं, इसलिए यह और भी महत्वपूर्ण हो जाता है।




मैं const उपयोग कर सकते हैं मैं कर सकते हैं मापदंडों के लिए का मतलब है कि उन्हें अपना मूल्य नहीं बदला जाना चाहिए। संदर्भ से गुजरते समय यह विशेष रूप से महत्वपूर्ण होता है समारोह के लिए const घोषित करता है कि फ़ंक्शन क्लास सदस्यों को नहीं बदलना चाहिए।




हो सकता है यह अभ्यस्त मान्य तर्क हो। लेकिन अगर हम फंक्शन कंपाइलर के अंदर एक कंस्ट्रक्शन वैल्यू के मूल्य को बढ़ाते हैं तो हमें एक त्रुटि देगी: " त्रुटि: पारेषण पैरामीटर का वेतन वृद्धि " इसलिए इसका मतलब है कि हम कंसल्टेंट कुंजी शब्द को कार्यों के अंदर हमारे चर को संशोधित करने के लिए रोक सकते हैं (जो हमें / केवल पढ़ने योग्य नहीं है)। इसलिए यदि हम गलती से संकलन समय संकलक पर किया है तो हमें यह बताना होगा। यह विशेष रूप से महत्वपूर्ण है अगर आप केवल एक ही नहीं है जो इस परियोजना पर काम कर रहा है।




एकमात्र पैरामीटर केवल तभी उपयोगी होता है जब पैरामीटर संदर्भ से पारित किया जाता है, या तो संदर्भ या संकेतक। जब संकलक एक निश्चित पैरामीटर को देखता है, तो यह सुनिश्चित करता है कि पैरामीटर में उपयोग किए जाने वाले फ़ंक्शन फ़ंक्शन के शरीर के भीतर संशोधित नहीं हैं। किसी को भी एक के रूप में मूल्य मान पैरामीटर क्यों बनाना चाहते हैं? :-)




यदि पैरामीटर मूल्य से पारित किया जाता है (और कोई संदर्भ नहीं है), तो आम तौर पर इसमें कोई फर्क नहीं पड़ता है कि पैरामीटर को कॉन्स्ट या नहीं घोषित किया गया है (जब तक कि यह संदर्भ सदस्य नहीं है - अंतर्निहित प्रकारों के लिए कोई समस्या नहीं)। यदि पैरामीटर एक संदर्भ या संकेतक है, तो आमतौर पर संदर्भित / पॉर्न-टू-मेमोरी की रक्षा करना बेहतर होता है, न ही सूचक (मुझे लगता है कि आप संदर्भ खुद को नहीं बना सकते हैं, ऐसा नहीं है कि यह महत्वपूर्ण है क्योंकि आप रेफरी नहीं बदल सकते हैं) । ऐसा लगता है कि आप जितना भी कर सकते हैं, उसे बचाने के लिए एक अच्छा विचार है। यदि कोई पैरामीटर केवल पीओडी (अंतर्निहित प्रकारों सहित) हैं, तो आप गलती करने के डर के बिना इसे छोड़ सकते हैं और उन्हें सड़क पर आगे बढ़ने की कोई संभावना नहीं है (उदाहरण के लिए आपके उदाहरण में बॉल्स पैरामीटर)।

मुझे .h / .cpp फ़ाइल घोषणा अंतर के बारे में पता नहीं था, लेकिन यह कुछ समझ में आता है। मशीन कोड स्तर पर, "const" कुछ भी नहीं है, इसलिए यदि आप एक समारोह (.h) में गैर- const के रूप में घोषित करते हैं, कोड समान होता है, जैसा कि आप const (अनुकूलन को एक तरफ) के रूप में घोषित करते हैं। हालांकि, यह आपको कंपाइलर को सूचीबद्ध करने में मदद करता है कि आप फ़ंक्शन (.ccp) के कार्यान्वयन के भीतर चर के वैल्यू को नहीं बदलेगा। यह उस मामले में आसान हो सकता है जब आप अंतरफलक से विरासत में ले जाते हैं जो परिवर्तन की अनुमति देता है, लेकिन आवश्यक कार्यक्षमता प्राप्त करने के लिए आपको पैरामीटर में बदलने की आवश्यकता नहीं है







संक्षेप में:

  • "आम तौर पर कॉन्स्ट पास-बाय-वैल्यू बेहिचक और भ्रामक है।" GOTW006 से
  • लेकिन आप उन्हें। सीपीपी में जोड़ सकते हैं क्योंकि आप चर के साथ करेंगे
  • ध्यान दें कि मानक पुस्तकालय const का उपयोग नहीं करता है जैसे std::vector::at(size_type pos) मानक पुस्तकालय के लिए क्या अच्छा है मेरे लिए अच्छा है



मैं ऐसे मापदंडों को नहीं लगाता जैसे - हर कोई पहले से जानता है कि बूलियन (एक बूलियन के विपरीत और) स्थिर है, इसलिए इसे जोड़कर लोगों को लगता है कि "रुको, क्या होगा?" या यहां तक ​​कि आप संदर्भ से पैरामीटर पास कर रहे हैं।




const के साथ याद करने की बात यह है कि चीजों को शुरू से ही बनाना आसान होता है, इसकी कोशिश करना और उन्हें बाद में डाल देना है

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

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




वास्तव में कोई मान-पैरामीटर "const" बनाने का कोई कारण नहीं है क्योंकि फ़ंक्शन केवल वैसे भी एक प्रतिलिपि को संशोधित कर सकता है।

"Const" का उपयोग करने का कारण यह है कि यदि आप संदर्भ से बड़े (उदाहरण के लिए बहुत सारे सदस्यों के साथ एक स्ट्रेट) गुजर रहे हैं, तो इस मामले में यह सुनिश्चित करता है कि फ़ंक्शन इसे संशोधित नहीं कर सकता; या बल्कि, यदि आप इसे पारंपरिक तरीके से संशोधित करने का प्रयास करते हैं, तो संकलक शिकायत करेगा। यह गलती से संशोधित किया जा रहा से बचाता है।




यदि आप मूल रूप से कोई मतलब नहीं है स्थिरांक के रूप में मान पैरामीटर द्वारा पास घोषित करने के लिए बुला समारोह के perspective.It से स्थिरांक निर्दिष्ट या नहीं मानकों मूल्य द्वारा पारित किया जा रहा है के रूप में, यह does not कोई फर्क।




अपने उदाहरण के सभी consts कोई उद्देश्य है। सी ++ पारित-दर-मूल्य डिफ़ॉल्ट रूप से है, इसलिए समारोह उन ints और बूलियन की प्रतियां हो जाता है। समारोह उन्हें संशोधित करता है यहां तक ​​कि अगर, फोन करने वाले का प्रति प्रभावित नहीं है।

इसलिए मैं क्योंकि अतिरिक्त consts से बचने चाहते हैं

  • वे redudant रहे
  • वे पाठ को अस्त-व्यस्त
  • उन्होंने मुझे बदलने के मामलों में जहां यह उपयोगी या कुशल हो सकता है में मूल्य में पारित करने से रोकने के।



मैं जानता हूँ कि सवाल यह है कि "एक सा" पुरानी लेकिन जैसा कि मैंने यह करवाते आया किसी और को भी भविष्य में ऐसा कर सकते हैं ... ... अभी भी मुझे शक है बेचारा यहाँ नीचे सूचीबद्ध मेरी टिप्पणी को पढ़ने के लिए होगा :)

मुझे ऐसा लगता है कि हम अभी भी बहुत सोच के सी-शैली रास्ते तक ही सीमित हैं। OOP Paradigma हम वस्तुओं, नहीं प्रकार के साथ चारों ओर खेलते हैं। कॉन्स्ट वस्तु एक गैर स्थिरांक वस्तु से धारणात्मक अलग हो सकता है, विशेष रूप से तार्किक-स्थिरांक (बिटवाइज़-स्थिरांक की तुलना में) के तौर पर। इस प्रकार, भले ही समारोह पैरामीटर के स्थिरांक शुद्धता है (शायद) एक से अधिक सतर्कता फली की मामले में यह नहीं तो वस्तुओं के मामले में है। एक समारोह के एक स्थिरांक वस्तु के साथ काम करता है यह इतना कहना चाहिए। निम्नलिखित कोड का टुकड़ा पर विचार करें

#include <iostream>

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SharedBuffer {
private:

  int fakeData;

  int const & Get_(int i) const
  {

    std::cout << "Accessing buffer element" << std::endl;
    return fakeData;

  }

public:

  int & operator[](int i)
  {

    Unique();
    return const_cast<int &>(Get_(i));

  }

  int const & operator[](int i) const
  {

    return Get_(i);

  }

  void Unique()
  {

    std::cout << "Making buffer unique (expensive operation)" << std::endl;

  }

};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void NonConstF(SharedBuffer x)
{

  x[0] = 1;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ConstF(const SharedBuffer x)
{

  int q = x[0];

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main()
{

  SharedBuffer x;

  NonConstF(x);

  std::cout << std::endl;

  ConstF(x);

  return 0;

}

ps .: आप का तर्क है कि (स्थिरांक) संदर्भ यहाँ अधिक उचित होगा और आप एक ही व्यवहार देता है हो सकता है। ठीक है, ठीक है। बस क्या मैं कहीं और देख सकते हैं से एक अलग तस्वीर दे रही है ...




एक VB.NET प्रोग्रामर 50 + उजागर काम करता है, और है कि कई मायनों स्थिरांक क्वालीफायर का उपयोग करता है एक ज फ़ाइल के साथ एक सी ++ प्रोग्राम का उपयोग करने की जरूरत है कि होने के नाते, यह पता करने के लिए जब एक चर ByRef या ByVal का उपयोग कर का उपयोग करने के लिए मुश्किल है।

बेशक कार्यक्रम लाइन जहां गलती की है पर एक अपवाद त्रुटि उत्पन्न करके आपको बताता है, लेकिन फिर आप अनुमान लगा जो 2-10 पैरामीटर की गलत है की जरूरत है।

तो अब मैं एक डेवलपर कि वे वास्तव में एक तरह से है कि VB.NET समारोह परिभाषाओं के सभी आसानी से बनाने के एक स्वचालित विधि की अनुमति देता है में अपने चर (ज फ़ाइल में) परिभाषित करना चाहिए समझाने की कोशिश की अरुचिकर कार्य किया है। वे तो smugly कहेंगे, "पढ़ें ... प्रलेखन।"

मैं एक awk स्क्रिप्ट है कि एक ज फ़ाइल को पार्स करता है, घोषित समारोह आदेशों के सभी बनाता है लिखा है, लेकिन एक संकेत के बिना के रूप में करने के लिए जो चर आर / हे बनाम आर / डब्ल्यू हैं, यह केवल आधा काम करता है।

संपादित करें:

किसी अन्य उपयोगकर्ता मैं निम्नलिखित द्वारा जोड़ा जा रहा के प्रोत्साहन पर;

यहाँ एक (IMO) का एक उदाहरण खराब ज प्रविष्टि का गठन है,

typedef int (EE_STDCALL *Do_SomethingPtr)( int smfID, const char* cursor_name, const char* sql );

मेरी स्क्रिप्ट से परिणामी वीबी;

    Declare Function Do_Something Lib "SomeOther.DLL" (ByRef smfID As Integer, ByVal cursor_name As String, ByVal sql As String) As Integer

नोट पहले पैरामीटर पर लापता "स्थिरांक"। इसके बिना, एक कार्यक्रम (या किसी अन्य डेवलपर) कोई आइडिया 1 पैरामीटर पारित किया जाना चाहिए है "ByVal।" "स्थिरांक" यह ज फ़ाइल स्वयं दस्तावेज़ीकृत कर देता है, ताकि अन्य भाषाओं का उपयोग कर डेवलपर्स आसानी से काम कर कोड लिख सकते हैं जोड़ कर।