सामग्री पर जाएँ
Topos Uranos

सारांश

यह पाठ अध्ययन करता है कि डेटा किन रास्तों से किसी फ़ंक्शन में प्रवेश करता है और उसके परिणाम किन रास्तों से बाहर आते हैं। डिफ़ॉल्ट रूप से C++ आर्ग्युमेंट को मान द्वारा पास करती है: पैरामीटर एक प्रति है, और फ़ंक्शन उसके साथ जो कुछ भी करे, वह असल चर तक नहीं पहुँचता। इसके विपरीत, रेफ़रेंस पहले से मौजूद किसी सेल का दूसरा नाम है, और वह फ़ंक्शन को कॉल करने वाले का चर बदलने देता है; कॉन्स्ट रेफ़रेंस किसी बड़े डेटा को उसकी प्रति बनाए बिना और उसे बदल पाए बिना पढ़ने देता है। कई परिणाम लौटाने के लिए लाइब्रेरी std::pair और std::tuple देती है, जिन्हें संरचित बाइंडिंग से प्राप्त किया जाता है। इसके बाद किसी नाम का स्कोप (वह कहाँ दिखता है) और किसी चर का जीवनकाल (वह कब मौजूद है) आते हैं, साथ में नाम को छिपाना और static लोकल चर, और अंत में वह रेफ़रेंस जो अपने चर के बाद भी बचा रहता है। इन सबको जोड़ने वाली अवधारणा प्रोग्राम के भागों के बीच डेटा का प्रवाह है: प्रति बनाम साझेदारी, और अलगाव की प्रणाली के रूप में नामों की दृश्यता।

अधिगम उद्देश्य

  1. यह पूर्वानुमान करना कि कोई फ़ंक्शन अपने आर्ग्युमेंट पर क्या प्रभाव डालता है, इस आधार पर कि वे मान द्वारा पास किए गए हैं या रेफ़रेंस द्वारा।
  2. हर पैरामीटर के पास करने का तरीक़ा चुनना (छोटे प्रकारों के लिए मान, बड़े डेटा के लिए कॉन्स्ट रेफ़रेंस, जो बदला जाए उसके लिए रेफ़रेंस) और चुनाव का औचित्य बताना।
  3. std::pair या std::tuple से कई परिणाम लौटाना और उन्हें संरचित बाइंडिंग से प्राप्त करना।
  4. किसी प्रोग्राम के हर चर का स्कोप और जीवनकाल निर्धारित करना, static लोकल चरों और किसी दूसरे चर द्वारा छिपाए गए चरों सहित।
  5. किसी ऐसे लोकल चर या अस्थायी मान के रेफ़रेंस को, जो अब मौजूद नहीं है, उसकी सूचना देने वाली कंपाइलर की चेतावनी के साथ पहचानना और ठीक करना।

मान द्वारा पास करना

पैरामीटर एक प्रति है

पाठ फ़ंक्शन ने दिखाया कि हर कॉल स्टैक पर एक फ़्रेम बनाती है, जिसमें फ़ंक्शन के पैरामीटर और लोकल चर होते हैं, और लौटते समय फ़्रेम ग़ायब हो जाता है। यह स्पष्ट करना बाक़ी है कि किसी पैरामीटर का उस आर्ग्युमेंट से क्या संबंध है जो उसे इनिशियलाइज़ करता है। C++ का डिफ़ॉल्ट उत्तर सबसे सरल है: पैरामीटर एक नया लोकल चर है, जिसे आर्ग्युमेंट के मान की एक प्रति से इनिशियलाइज़ किया जाता है। यदि ऐसा है, तो अपने पैरामीटर बदलने वाला फ़ंक्शन अपनी प्रतियाँ बदलता है, और कॉल करने वाले के चर नहीं बदलते। नीचे दिया गया प्रोग्राम इसे एक ऐसे फ़ंक्शन से परखता है जो दो पूर्णांकों की अदला-बदली करने की कोशिश करता है।

C++ प्रोग्राम
#include <print>​// a और b की अदला-बदली की कोशिश करता है; केवल उनकी प्रतियाँ बदलती हैं।void swapValues(int a, int b){    const int saved{a};    a = b;    b = saved;    std::println("भीतर: a = {}, b = {}", a, b);}​int main(){    int x{1};    int y{2};    swapValues(x, y);    std::println("बाद में: x = {}, y = {}", x, y);}
आउटपुट
भीतर: a = 2, b = 1बाद में: x = 1, y = 2

फ़ंक्शन के भीतर अदला-बदली ठीक से होती है; कॉल के बाद x और y अपने मान बनाए रखते हैं। कंपाइलर चेतावनी नहीं देता, क्योंकि चेतावनी देने लायक़ कुछ है ही नहीं: कोड दो लोकल चरों की अदला-बदली करता है जो उसके समाप्त होने पर ग़ायब हो जाते हैं। चित्र कॉल के दौरान स्टैक के फ़्रेमों का अनुसरण करता है।

उदाहरणदो फ़्रेम, चार सेल

main के फ़्रेम में x और y हैं; कॉल उसके ऊपर swapValues का फ़्रेम बनाती है, जिसके अपने सेल हैं।

प्रमाण

  1. कॉल से पहले main के फ़्रेम में दो सेल हैं: 1 वाला x और 2 वाला y।

  2. कॉल swapValues का फ़्रेम बनाती है। उसके पैरामीटर a और b नए सेल हैं, और उनमें आर्ग्युमेंट के मान कॉपी होते हैं: 1 और 2। इस क्षण से a और x के बीच कोई संबंध नहीं बचता, सिवाय इसके कि दोनों एक ही मान से शुरू हुए थे।

  3. लोकल चर saved उसी फ़्रेम में बनता है और a की एक प्रति रखता है।

  4. दो असाइनमेंट a और b की अदला-बदली करते हैं। जो सेल बदलते हैं वे सब ऊपर वाले फ़्रेम में हैं; main के सेलों को छुआ नहीं जाता।

  5. लौटते समय swapValues का फ़्रेम, उसमें हुई अदला-बदली समेत, पूरा का पूरा ग़ायब हो जाता है। x और y अब भी 1 और 2 हैं।

प्रति किस चीज़ की रक्षा करती है

मान द्वारा पास करना कोई दोष नहीं, बल्कि वह नियम है जो फ़ंक्शनों को विवेकपूर्ण बनाता है। पहला, आर्ग्युमेंट केवल चर नहीं, कोई भी व्यंजक हो सकता है: swapValues(x + 1, 7) वैध है, क्योंकि पैरामीटर एक मान से इनिशियलाइज़ होता है, वह मान कहीं से भी आए। दूसरा, कॉल करने वाला बॉडी पढ़े बिना, घोषणा से ही जानता है कि उसके चर नहीं बदलेंगे। तीसरा, फ़ंक्शन के भीतर पैरामीटर एक और लोकल चर है, जो बाहर कोई परिणाम छोड़े बिना कार्य-चर का काम कर सकता है।

C++ प्रोग्राम
#include <print>​// n के दाशमिक अंकों की संख्या।// पूर्व-शर्त: n >= 0।// पश्च-शर्त: n के अंकों की संख्या लौटाता है (0 के लिए 1)।int digitCount(int n){    int count{1};    while (n >= 10) {        n = n / 10;        ++count;    }    return count;}​int main(){    const int population{48'210};    std::println("{} में {} अंक हैं", population, digitCount(population));}
आउटपुट
48210 में 5 अंक हैं

फ़ंक्शन अपने पैरामीटर को 10 से तब तक भाग देकर नष्ट करता है जब तक उसमें एक ही अंक न रह जाए; चूँकि वह एक प्रति है, population अक्षुण्ण रहता है और const हो सकता है। इससे पढ़ने का एक नियम निकलता है जो पूरे पाठ्यक्रम में लागू होता है: यदि किसी पैरामीटर में वह चिह्न & नहीं है जिसका अध्ययन आगे वाले अनुभाग में होगा, तो फ़ंक्शन उसके साथ कुछ भी करे, कॉल करने वाले का चर नहीं बदल सकता।