2010-12-08 19 views
6

यह माध्यम से एक series of SO questions आज स्पष्ट हो गया है कि मैं केवल संकेत दिए गए, संदर्भ, और मूल्यों की वास्तविक प्रकृति के एक गरीब समझ है।संदर्भ बनाम पॉइंटर्स को समझना। यह क्यों काम करता है?

निम्नलिखित कोड पर विचार करें:

int* p = new int(3); 
int& r = *p; 

cout << " p = " << p << "\t*p = " << *p << endl; 
cout << "&r = " << &r << "\t r = " << r << endl; 

delete p; 

cout << "&r = " << &r << "\t r = " << r << endl; 

int v = 4; 
r = v; 

cout << "&r = " << &r << "\t r = " << r << endl; 

इस के लिए उत्पादन

p = 0x1001000b0 *p = 3 
&r = 0x1001000b0  r = 3 
&r = 0x1001000b0  r = 3 
&r = 0x1001000b0  r = 4 

है बात मुझे समझ नहीं आता है क्यों दूसरी बार मैं संदर्भ के मूल्य प्रिंट मैं डॉन एक त्रुटि नहीं है। संदर्भ के मान से संबंधित सूचक पहले से ही हटा दिया गया है। मेरे previous question से, मैंने लगभग खुद को आश्वस्त किया था कि r = x जैसे किसी भी कथन मान के स्थान पर x की एक प्रति बनाता है। हालांकि, अगर यह मामला था तो p और &r अलग-अलग पते होंगे, है ना? अगर मैंने पहले ही 0x100100b0 पर डिलीट बुलाया है, तो मैं इसका उपयोग कैसे कर सकता हूं?

सही या गलत: एक संदर्भ एक पते पर मूल्य के उपनाम के समान ही है।

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

+9

अपरिभाषित व्यवहार के बारे में बात यह है कि इसे पूरी तरह से ठीक काम करने की अनुमति है। :) –

+0

सच, झूठा, और क्या @ करल ने कहा। यह अनिर्धारित व्यवहार है जो इस बार दुर्घटनाग्रस्त नहीं हुआ। – aschepler

+0

@ आप लोग महान हैं! तब मुझे लगता है कि मैं अंत में समझता हूं। – JnBrymn

उत्तर

11

भले ही आपको कोई त्रुटि न हो, तो परिणाम अभी भी अनिर्धारित हैं। अपरिभाषित व्यवहार का मतलब है कि कुछ भी हो सकता है, जिसमें आपका प्रोग्राम सही तरीके से काम करना जारी रखता है।

एक संदर्भ एक पते पर मूल्य के उपनाम के समान ही है।

यह प्रभावी रूप से सच है। यह कहना अधिक सही होगा कि संदर्भ ऑब्जेक्ट (मान नहीं) के लिए उपनाम है।

आप एक ही पते के सूचक के रूप संदर्भित मूल्य, रहता है (जैसा कि मैंने ऊपर है) को हटाते हैं, तो कोई अपरिभाषित व्यवहार हो जाएगा,

यह भी सच है। जब तक आप संदर्भ का उपयोग करने का प्रयास नहीं करते हैं तब तक कोई परिभाषित व्यवहार नहीं होता है। जब आप संदर्भ का उपयोग करने का प्रयास करते हैं (उदाहरण के लिए, &r के माध्यम से), तो आपको अपरिभाषित व्यवहार मिलता है।

यदि आप ऑब्जेक्ट को नष्ट करने के बाद संदर्भ का उपयोग करने का प्रयास नहीं करते हैं, तो कोई अपरिभाषित व्यवहार नहीं है।

कोई भी उस संदर्भ को तब तक ओवरराइट नहीं करेगा जब तक संदर्भ मौजूद न हो।

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

+0

ज्ञान। धन्यवाद! – JnBrymn

+0

एक और सवाल, संदर्भ नहीं है 'आर = वी;' संदर्भ? – Praetorian

+2

@Praetorian: नहीं, यह 'v' (जो 4 है) के मान को संदर्भित करता है जिसे संदर्भ 'आर' द्वारा संदर्भित ऑब्जेक्ट में दिया जाता है। एक संदर्भ को संशोधित करना असंभव है। –

0

पहले एक सत्य है:

  • एक संदर्भ वास्तव में एक मूल्य के लिए एक उपनाम है। संदर्भ के विशिष्ट कार्यान्वयन कि तथ्य नहीं बदलता है, और इस पर भरोसा नहीं किया जाना चाहिए।

दूसरा गलत है:

  • आप एक ही पते पर एक सूचक को हटाते हैं, तो क्या होता है जो आपने पहले बनाया संदर्भ का उपयोग पर ही निश्चित स्रोत भाषा कल्पना है। मेरा मानना ​​है कि सी ++ में मामला "अपरिभाषित व्यवहार" है। क्या आपके उदाहरण में होता है कि ('मैं यहाँ hypothesizing मीटर), संदर्भ सूचक के रूप में लागू किया गया है और इसलिए यह अभी भी जब एक int के रूप में व्याख्या मान 3 होने स्मृति के ब्लॉक की ओर इशारा करता है। उस ब्लॉक को संभावित भविष्य के उपयोग के लिए ढेर में छोड़ दिया गया है, इसलिए इसमें कोई गारंटी नहीं है कि इसमें वास्तव में 3 या संदर्भित प्रकार के लिए कानूनी मूल्य भी है (हालांकि निश्चित रूप से प्रत्येक संभव मूल्य int के लिए कानूनी है - यह हो सकता है हालांकि एक वर्ग प्रकार रहा है)। अभ्यास में, के बाद से मूल्य और कुछ के साथ ओवरराइट नहीं कर रहा था, तब भी आप एक "सार्थक" परिणाम जब संदर्भ का उपयोग कर मिलता है। हालांकि, यह "संयोग" के द्वारा होता है।

अद्यतन: मैं पहले सवाल का जवाब में गलत था, इस सवाल का जवाब पर फिर से काम किया है।

0

A reference is the same thing as an alias to the value at an address.

सच

True or false: If you delete a pointer to the same address as a referenced value resides, (as I do above), then no undefined behavior will occur, and no one will ever overwrite that address as long as the reference exists.

झूठी

int v = 4; 
r = v; 

संकलित क्योंकि आर एक पूर्णांक के लिए एक संदर्भ है।

हालांकि, जब आप किसी भी संदर्भ बिंदु को हटाते हैं और फिर इसका उपयोग करने का प्रयास करते हैं, तो यह अपरिभाषित व्यवहार है!

0

आपका पहला प्रश्न उत्तर देने के लिए थोड़ा अस्पष्ट है। पते पर मूल्य के लिए उपनाम क्या है?

दूसरा निश्चित रूप से गलत है। स्मृति जहां पी ओर इशारा करते हुए किया गया था मुक्त कर दिया गया था, और पुन: उपयोग किया जा सकता है। ऐसा होता है कि यह अभी तक नहीं बदला है। यह r का उपयोग करने के लिए अपरिभाषित है, और r = v अपरिवर्तित आर और प्रतिलिपि बनाम मूल्य (जिसे अपरिभाषित भी किया गया था - क्रैश हो सकता था)।

जब कुछ अपरिभाषित होता है, तो इसका मतलब यह नहीं है कि आपको कोई त्रुटि मिलेगी। इसका मतलब है कि आपको प्राप्त होने वाले किसी भी व्यवहार को विनिर्देश माना जाता है। दुर्घटनाग्रस्त या काम कर रहे दोनों स्वीकार्य "अनिर्धारित" व्यवहार कर रहे हैं।

0

सही या गलत: एक संदर्भ किसी पते पर मूल्य के उपनाम के समान ही है।

गलत: इसका पता पते से कोई लेना देना नहीं है (यह एक कार्यान्वयन विस्तार है)।

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

झूठी। यह एक चर के संदर्भ का उपयोग करने के लिए अपरिभाषित व्यवहार है जो अब ज़िंदा नहीं है। अलग-अलग प्रकार के चर अलग-अलग समय पर मर जाते हैं।

  • स्कोप के अंत में स्वत: संग्रहण अवधि चर मर जाते हैं।
  • स्थिर भंडारण अवधि चर मुख्य निकास
  • गतिशील भंडारण अवधि चर के मरने के बाद सृजन के विपरीत क्रम में मर जाते हैं जब वे स्मृति के भीतर रहते हैं।
+1

पहला ऐसा तकनीकी रूप से सच है, मुझे लगता है। एक संदर्भ किसी ऑब्जेक्ट के लिए उपनाम है और ऑब्जेक्ट एक मान है और उसका पता है (शायद यह कहना बेहतर होगा कि "ऑब्जेक्ट का मान है"? मुझे यकीन नहीं है)। ओपी शब्द "उपनाम" का उपयोग करता है, जो सही है। –

+0

हां लेकिन किसी ऑब्जेक्ट के लिए उपनाम है। वस्तु का प्रतिनिधित्व कैसे किया जाता है संदर्भ का उपयोग कर कोड के लिए अदृश्य है (यह रजिस्टर में हो सकता है)। –

1

एक संदर्भ एक वस्तु के लिए एक उपनाम है। यदि उस ऑब्जेक्ट का जीवनकाल समाप्त हो गया है, तो उस ऑब्जेक्ट का संदर्भ मान्य होना बंद हो जाता है। तथ्य यह है कि यह प्रतीत होता है 'काम सिर्फ एक संयोग है करने के लिए - -

अपने उदाहरण में, अपरिभाषित व्यवहार में delete p आपरेशन परिणाम के बाद r referecen का उपयोग r का उपयोग कर उस बिंदु के बाद बस के रूप में उस बिंदु के बाद *p का उपयोग कर (के रूप में अमान्य है और likey समान व्यवहार का परिणाम देगा

उदाहरण के लिए, साथ r ऐसा दिखाई देता है के रूप में *p के साथ एक ही thigns करने के लिए अपने कार्यक्रम को संशोधित:।

#include <iostream> 
using namespace std; 

int main() 
{ 
    int* p = new int(3); 
    int& r = *p; 

    cout << " p = " << p << "\t*p = " << *p << endl; 
    cout << "&r = " << &r << "\t r = " << r << endl; 

    delete p; 

    cout << " p = " << p << "\t*p = " << *p << endl; 
    cout << "&r = " << &r << "\t r = " << r << endl; 

    int v = 4; 

    *p = v+1; 
    cout << " p = " << p << "\t*p = " << *p << endl; 

    r = v; 
    cout << "&r = " << &r << "\t r = " << r << endl; 
} 

आउटपुट:

p = 0x3f1730 *p = 3 
&r = 0x3f1730 r = 3 
p = 0x3f1730 *p = 4134736 
&r = 0x3f1730 r = 4134736 
p = 0x3f1730 *p = 5 
&r = 0x3f1730 r = 4 

आप *p उपयोग करने के बाद वस्तु हटा दिया गया है के लिए समान व्यवहार है कि देखेंगे (और यह बस के रूप में अवैध है)। कि पहुँच गलत सूचक या गलत संदर्भ के माध्यम से होता है कि क्या

सभी मामलों में, वस्तु तक पहुँचने के बाद इसे नष्ट कर दिया गया है, अपरिभाषित व्यवहार है।

+0

आखिरकार उस स्मृति पते पर कुछ और लिखता है क्योंकि हमने इसे मुक्त किया है, और फिर दुनिया समाप्त होती है। सही? – JnBrymn

+0

@ जॉन: या आप उस पल को क्रैश कर सकते हैं जब आप ऑब्जेक्ट को पढ़ते हैं या लिखते हैं क्योंकि ऑब्जेक्ट के लिए वर्चुअल मेमोरी एड्रेस अब मान्य नहीं होगा (यह डिबगिंग स्टैंडपॉइंट के लिए बेहतर है, क्योंकि यह आपको तुरंत बताएगा कि आपके पास कुछ बुरा किया)। या कुछ भी बुरा नहीं देखा जा सकता है (यह सबसे बुरा मामला है, क्योंकि समस्या कई हफ्तों तक और बाद में कई प्रतिष्ठानों तक नहीं देखी जा सकती है)। –

1

सही या गलत: एक संदर्भ एक पते पर मूल्य के लिए एक उपनाम के रूप में एक ही बात है।

Errr ... सच? आपकी शब्दावली यह अस्पष्ट बनाती है, लेकिन मुझे लगता है कि मैं जो पूछ रहा हूं उसे मिला।

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

झूठी। आप केवल अनलॉक किए गए मेमोरी के बाद सही मूल्य पढ़ने से दूर हो रहे हैं क्योंकि आपका सी ++ कार्यान्वयन स्मृति प्रबंधन के बारे में नहीं है और आप इसकी "वैधता" की समाप्ति के बाद इसे एक्सेस कर रहे हैं।

आप देखते हैं कि संकलन समय पर कंपाइलर के भविष्यवाणी करने का कोई तरीका नहीं है कि आप इस गंदे चाल को खींचने वाले हैं और रन-टाइम मेमोरी सुरक्षा माइक्रोमैनेजमेंट महंगा है।

तो, यह बुरा अभ्यास क्यों है और क्या गलत हो सकता है? 1) यदि आपके "डिलीट पी" और तीसरे कोउट के बीच में आप "मेमोरी" और "डिलीट" कॉल के साथ बड़ी मेमोरी-भारी परिचालन करते हैं - वहां एक वसा मौका है जो वास्तविक स्मृति बिंदु "आर" का संदर्भ दे रहा है समझौता किया जाएगा (ऑपरेटिंग सिस्टम से मुक्त मेमोरी के कारण इसका मूल्य बदल गया है या पूरी तरह से अनुपलब्ध है - जो सामान्य सुरक्षा गलती और आपके ऐप क्रैश का कारण बनता है)

2) यदि आप कुछ एपनोइड (या संसाधन दुर्लभ) में अपना ऐप संकलित और चलाते हैं पर्यावरण आपको एक दुर्घटना मिलेगी क्योंकि सिस्टम ट्रैक करता है कि "ऐप" मान जितना कम पैमाने पर आपके ऐप से कौन सी मेमोरी संबंधित है।

यदि आप अधिक जानकारी चाहते हैं तो आप "सी ++ ढेर" और "सी ++ मेमोरी प्रबंधन" विषयों को देख सकते हैं।

संबंधित मुद्दे