दिलचस्प पोस्ट
एक सीमांकक के आधार पर तारों की एक सरणी में एक स्ट्रिंग विभाजित करें मैं Pandas read_csv फ़ंक्शन में लोड पर लाइनों को कैसे फ़िल्टर कर सकता हूं? Numpy array में निकटतम मान ढूंढें उनके वर्णमाला क्रम से तार की तुलना करना मैं एक HTML ईमेल कैसे भेजूं? वादा परिणाम से नोड मॉड्यूल निर्यात करना मैं एंड्रॉइड में एक डेटाबेस कैसे बनाऊं? कहाँ और क्यों int एक = नया int का उपयोग करें? क्यों std :: function समानता तुलनीय नहीं है? प्लेबैक वीडियो पूर्ण स्क्रीन क्या कोणीय मार्गों के वैकल्पिक पैरामीटर मान हैं? XSD स्कीमा का उपयोग करते हुए एक्सएमएल सत्यापन बाइनरी शाब्दिक? कस्टम नियंत्रण में अवांछित गुणों को छिपाते हुए App_Code में रहने वाले वर्ग पहुंच योग्य नहीं हैं

कैसे सी + + संदर्भ देखो, स्मृति-वार?

दिया हुआ:

int i = 42; int j = 43; int k = 44; 

वे चर पते देखकर जो हम जानते हैं कि प्रत्येक व्यक्ति 4 बाइट्स लेता है (अधिकांश प्लेटफ़ॉर्म पर)।

हालांकि, पर विचार:

 int i = 42; int& j = i; int k = 44; 

हम देखेंगे कि वेरिएबल i वास्तव में 4 बाइट्स लेता है, लेकिन j कोई नहीं लेता है और k फिर से 4 बाइट स्टैक पर ले जाता है।

यहां क्या हो रहा है? ऐसा लगता है कि j बस क्रमशः में गैर-मौजूद है और एक संदर्भ के बारे में मुझे फंक्शन तर्क के रूप में क्या मिलता है? उस स्टैक पर कुछ जगह लेनी होगी

और जब हम उस पर हैं – मैं एक सरणी या संदर्भ को परिभाषित क्यों नहीं कर सकता?

 int&[] arr = new int&[SIZE]; // compiler error! array of references is illegal 

वेब के समाधान से एकत्रित समाधान "कैसे सी + + संदर्भ देखो, स्मृति-वार?"

हर जगह संदर्भ जम्मू का सामना करना पड़ता है, इसे I के पते के साथ बदल दिया जाता है । तो मूल रूप से संदर्भ सामग्री का पता संकलन समय पर हल होता है, और इसे समय पर एक सूचक की तरह dereference की आवश्यकता नहीं है।

बस मैं स्पष्ट करने के लिए कि मैं के पते से क्या मतलब है :

 void function(int& x) { x = 10; } int main() { int i = 5; int& j = i; function(j); } 

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

सरणी भाग के लिए मानकों का कहना है:

सी ++ मानक 8.3.2 / 4:

संदर्भों का कोई संदर्भ नहीं होगा, संदर्भों का कोई क्रम नहीं होगा, और संदर्भों के लिए कोई संकेत नहीं होगा।

संदर्भों का सरणी अवैध क्यों है?

कैसे सी + + संदर्भ देखो, स्मृति-वार?

यह नहीं है सी ++ मानक केवल कहता है कि उसे कैसे व्यवहार करना चाहिए, यह कैसे लागू नहीं किया जाना चाहिए।

सामान्य मामले में, कंपाइलर आमतौर पर पॉइंटर्स के रूप में संदर्भ लागू करते हैं लेकिन उनके पास आम तौर पर अधिक जानकारी है कि कोई संदर्भ क्या इंगित कर सकता है, और अनुकूलन के लिए इसका उपयोग कर सकता है।

याद रखें कि एक संदर्भ के लिए केवल एक आवश्यकता है कि यह संदर्भित वस्तु के लिए उपनाम के रूप में व्यवहार करता है इसलिए यदि संकलक को इस कोड का सामना करना पड़ता है:

 int i = 42; int& j = i; int k = 44; 

यह देखता है कि "वेरिएबल में एक पॉइंटर बनाने के लिए" नहीं है (हालांकि इस तरह से यह संकलक कुछ मामलों में इसे लागू करने के लिए चुन सकता है), बल्कि "प्रतीक तालिका में एक नोट j कि j अब i लिए एक उपनाम है "

कंपाइलर को j लिए एक नया चर बनाने की ज़रूरत नहीं है, यह याद रखना जरूरी है कि जब भी j को अब से संदर्भित किया जाता है, तो इसे वास्तव में स्वैप करना चाहिए और i इसके बजाय उपयोग करना चाहिए।

संदर्भों की एक सरणी बनाने के लिए, आप ऐसा नहीं कर सकते क्योंकि यह बेकार और अर्थहीन होगा

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

तो अगर यह किया जा सकता है, तो आप कुछ भी नहीं संदर्भ के सरणी के साथ समाप्त होगा। और आप उन्हें कुछ संदर्भ देने में बदलने में असमर्थ होंगे क्योंकि उन्हें पहले ही आरम्भ किया गया था

व्यवहार में, एक संदर्भ एक सूचक के समतुल्य है, सिवाय इसके कि संदर्भों को कैसे उपयोग करने की अनुमति दी जाती है, पर अतिरिक्त बाधाएं एक संकलक को और अधिक मामलों में "इसे दूर करने के लिए" की अनुमति दे सकती हैं (इस पर निर्भर करता है कि कम्पाइलर कैसे स्मार्ट है, इसकी अनुकूलन सेटिंग्स, आदि आदि)

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

ऐसा कुछ जो कि कहीं और पारित करने में उल्लिखित है – कंपाइलर को कुछ संग्रहण स्थान को एक संदर्भ में समर्पित करने के लिए कैसे प्राप्त करें:

 class HasRef { int &r; public: HasRef(int &n) : r(n) { } }; 

यह कंपाइलर को इसे केवल संकलन-समय के उपनाम (एक ही भंडारण के लिए एक वैकल्पिक नाम) के रूप में व्यवहार करने का अवसर से इनकार करता है।

यह समझाने के लिए विधानसभा का उपयोग करने के लिए क्षमा करें, लेकिन मुझे लगता है कि संदर्भों को समझने का यह सबसे अच्छा तरीका है

  #include <iostream> using namespace std; int main() { int i = 10; int *ptrToI = &i; int &refToI = i; cout << "i = " << i << "\n"; cout << "&i = " << &i << "\n"; cout << "ptrToI = " << ptrToI << "\n"; cout << "*ptrToI = " << *ptrToI << "\n"; cout << "&ptrToI = " << &ptrToI << "\n"; cout << "refToNum = " << refToI << "\n"; //cout << "*refToNum = " << *refToI << "\n"; cout << "&refToNum = " << &refToI << "\n"; return 0; } 

इस कोड का उत्पादन इस तरह है

  i = 10 &i = 0xbf9e52f8 ptrToI = 0xbf9e52f8 *ptrToI = 10 &ptrToI = 0xbf9e52f4 refToNum = 10 &refToNum = 0xbf9e52f8 

आइए हम चीजों को देखने के लिए देखें (मैं इसके लिए जीडीबी का इस्तेमाल किया था। 8 9 और 10 यहां पंक्ति संख्या कोड हैं)

 8 int i = 10; 0x08048698 <main()+18>: movl $0xa,-0x10(%ebp) 

यहां $0xa 10 (दशमलव) है जो हम आई को बता रहे हैं। -0x10(%ebp) का अर्थ ebp register -16 (दशमलव) की सामग्री है। -0x10(%ebp) i स्टैक पर पता करने के लिए इंगित करता है।

 9 int *ptrToI = &i; 0x0804869f <main()+25>: lea -0x10(%ebp),%eax 0x080486a2 <main()+28>: mov %eax,-0x14(%ebp) 

i ptrToI पते का निरुपित करें ptrToI फिर से -0x14(%ebp) पते पर स्थित स्टैक पर है, जो कि ebp -20 (दशमलव) है।

 10 int &refToI = i; 0x080486a5 <main()+31>: lea -0x10(%ebp),%eax 0x080486a8 <main()+34>: mov %eax,-0xc(%ebp) 

अब यहाँ पकड़ है! लाइन 9 और 10 के -0x14(%ebp) की तुलना करें और आप देखेंगे कि, -0x14(%ebp) -0xc(%ebp) को लाइन नंबर 10 -0xc(%ebp) -0xc(%ebp) में -0xc(%ebp) -0x14(%ebp) द्वारा बदल दिया गया है, -0xc(%ebp) का पता। इसे स्टैक पर आवंटित किया गया है। लेकिन आप इस पते को कभी भी अपने कोड से नहीं प्राप्त कर पाएंगे क्योंकि आपको पते को जानने की जरूरत नहीं है।

इसलिए; एक संदर्भ स्मृति पर कब्जा नहीं करता है इस मामले में यह स्टैक मेमोरी है क्योंकि हमने इसे एक स्थानीय चर के रूप में आवंटित किया है। यह कितना मेमोरी है? जितना अधिक एक संकेतक रहता है

अब देखते हैं कि हम संदर्भ और संकेतों का उपयोग कैसे करते हैं। सादगी के लिए मैंने विधानसभा स्निपेट का केवल एक हिस्सा दिखाया है

 16 cout << "*ptrToI = " << *ptrToI << "\n"; 0x08048746 <main()+192>: mov -0x14(%ebp),%eax 0x08048749 <main()+195>: mov (%eax),%ebx 19 cout << "refToNum = " << refToI << "\n"; 0x080487b0 <main()+298>: mov -0xc(%ebp),%eax 0x080487b3 <main()+301>: mov (%eax),%ebx 

अब ऊपर की दो पंक्तियों की तुलना करें, आप हड़ताली समानता देखेंगे। -0xc(%ebp) का वास्तविक पता है जो आपके लिए कभी भी पहुंच नहीं सकता है सरल शब्दों में, यदि आप सामान्य सूचक के रूप में संदर्भ के बारे में सोचते हैं, तो संदर्भ संदर्भ में संदर्भ के आधार पर दिए गए पते पर मूल्य लाने की तरह है। जिसका अर्थ है कि नीचे दिए गए दो लाइन कोड आपको समान परिणाम देगा

 cout << "Value if i = " << *ptrToI << "\n"; cout << " Value if i = " << refToI << "\n"; 

अब इसकी तुलना करें

 15 cout << "ptrToI = " << ptrToI << "\n"; 0x08048713 <main()+141>: mov -0x14(%ebp),%ebx 21 cout << "&refToNum = " << &refToI << "\n"; 0x080487fb <main()+373>: mov -0xc(%ebp),%eax 

मुझे लगता है कि आप यह देख सकते हैं कि यहाँ क्या हो रहा है। यदि आप &refToI लिए पूछते हैं, तो -0xc(%ebp) पते स्थान की सामग्री लौटा दी जाती है और -0xc(%ebp) है जहां refToi रहता है और इसकी सामग्री कुछ भी नहीं है लेकिन i इसका पता नहीं

एक आखिरी चीज, यह लाइन क्यों टिप्पणी की गई है?

 //cout << "*refToNum = " << *refToI << "\n"; 

क्योंकि *refToI की अनुमति नहीं है और यह आपको एक संकलन समय त्रुटि देगा।

सन्दर्भ वास्तव में शारीरिक रूप से अस्तित्व में नहीं होते हैं जब तक कि उन्हें एक भौतिक अभिव्यक्ति (यानी कुल मिलाकर एक सदस्य के रूप में) की आवश्यकता हो।

इसके बाद के संस्करण के कारण संदर्भों की एक सरणी अवैध है। लेकिन कुछ भी आपको स्ट्रैक्ट्स / कक्षाओं के सरणी बनाने से रोकता है जो संदर्भ के सदस्य हैं।

मुझे यकीन है कि कोई मानक खंड बताएगा जो इसका सबूत देता है।

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