2012-04-09 4 views
18

सी ++ में, जब ऑब्जेक्ट को "दायरे से बाहर" कहा जाता है?ऑब्जेक्ट "स्कोप से बाहर" कब होता है?

अधिक विशेष रूप से, यदि मेरे पास एकमात्र लिंक की गई सूची थी, तो एक सूची नोड ऑब्जेक्ट को "दायरे से बाहर" के रूप में परिभाषित करने के लिए क्या परिभाषित किया जाएगा? या यदि कोई ऑब्जेक्ट मौजूद है और किसी चर 'ptr' द्वारा संदर्भित किया जा रहा है, तो क्या यह कहना सही है कि ऑब्जेक्ट को "स्कोप से बाहर" के रूप में परिभाषित किया गया है जब संदर्भ हटा दिया गया है या किसी भिन्न ऑब्जेक्ट को इंगित किया गया है?

अद्यतन: किसी ऑब्जेक्ट को मानना ​​एक वर्ग है जिसमें एक कार्यान्वित विनाशक है। क्या विनाशक को उस क्षण को बुलाया जाएगा जब वस्तु दायरे से निकलती है?

if (myCondition) { 
    Node* list_1 = new Node (3); 
    Node* list_2 = new Node (4); 
    Node* list_3 = new Node (5); 

    list_1->next = list_2; 
    list_2->next = list_3; 
    list_3->next = null; 
} 

दूसरे शब्दों में, नोड list_1 द्वारा की ओर इशारा किया जा रहा है कि इस लाइन के बाद अपनी नाशक फोन:

नोड * list_1 = नए नोड (3);

?

+1

आपका अद्यतन सवाल एक बहुत अच्छा एक है, और जवाब है नहीं। जब कोई सूचक स्कोप से बाहर हो जाता है, तो ऑब्जेक्ट का विनाशक जिस पर यह इंगित कर रहा है ** ** ** स्वचालित रूप से नहीं बुलाया जाता है। आपको इसे स्वयं कॉल करना होगा, और ऐसा तब होता है जब आप स्मृति को मुक्त करने के लिए नोड पर 'हटाएं' कहते हैं। जब आप सार्थक विनाशक कार्यान्वयन के साथ ऑब्जेक्ट्स में पॉइंटर्स की सरणी या सूची रखते हैं, तो यह ध्यान में रखना एक अच्छी बात है। सौभाग्य से, चूंकि आपको इन्हें स्वयं भी 'मुक्त' करना है, इसलिए आप विनाशकों को ट्रिगर करेंगे। –

+0

वैसे, अगर आपको वास्तव में किसी चीज़ के लिए एक लिंक्ड सूची की आवश्यकता है, तो आप अपनी खुद की कस्टम लिंक्ड सूची की तुलना में std :: सूची का उपयोग करके बहुत बेहतर हैं। – DSimon

+1

मुझे 'मुक्त' के बजाय 'हटाएं' कहा जाना चाहिए था। 'मुक्त' को अनदेखा करें, यह सी विरासत है। ढेर आवंटन/हटाने के लिए केवल 'नया' और 'हटाएं' का प्रयोग करें। –

उत्तर

41

पहले, याद रखें C++ वस्तुओं हो सकता है कि ढेर पर या तो ढेर पर या पर बनाया गया।

एक स्टैक फ्रेम (या स्कोप) एक बयान द्वारा परिभाषित किया गया है। यह एक फ़ंक्शन या फ्लो कंट्रोल ब्लॉक (while/if/for इत्यादि के रूप में छोटा हो सकता है) के रूप में बड़ा हो सकता है। एक मनमाने ढंग से {} कोड के मनमानी ब्लॉक को संलग्न करने वाली जोड़ी भी एक ढेर फ्रेम का गठन करती है। एक फ्रेम के भीतर परिभाषित कोई स्थानीय वैरिएबल उस फ्रेम से बाहर निकलने के बाद गुंजाइश से बाहर हो जाएगा। जब एक स्टैक वैरिएबल गुंजाइश से बाहर हो जाता है, तो इसके विनाशक को बुलाया जाता है।

तो यहाँ

ढेर फ्रेम (एक समारोह के निष्पादन) और एक स्थानीय चर के भीतर घोषित, जो एक बार स्टैक फ्रेम बाहर निकलता क्षेत्र से बाहर जाना होगा का एक उत्कृष्ट उदाहरण है - एक बार समारोह खत्म:

void bigSideEffectGuy() { 
    BigHeavyObject b (200); 
    b.doSomeBigHeavyStuff(); 
} 
bigSideEffectGuy(); 
// a BigHeavyObject called b was created during the call, 
// and it went out of scope after the call finished. 
// The destructor ~BigHeavyObject() was called when that happened. 

if (myCondition) { 
    Circle c (20); 
    c.draw(); 
} 
// c is now out of scope 
// The destructor ~Circle() has been called 

के एक ढेर-निर्मित वस्तु के लिए एक ही रास्ता "दायरे में रहने" के बाद फ्रेम से बाहर निकल गया है:

एक उदाहरण है जहाँ हम देखते हैं एक ढेर फ्रेम सिर्फ एक if बयान के शरीर किया जा रहा है अगर यह एक समारोह का वापसी मूल्य है। लेकिन यह वास्तव में "गुंजाइश में शेष नहीं है" क्योंकि वस्तु की प्रतिलिपि बनाई जा रही है। तो मूल दायरे से बाहर चला जाता है, लेकिन एक प्रति बना दिया जाता है। उदाहरण:

Circle myFunc() { 
    Circle c (20); 
    return c; 
} 
// The original c went out of scope. 
// But, the object was copied back to another 
// scope (the previous stack frame) as a return value. 
// No destructor was called. 

अब, एक वस्तु को ढेर पर भी घोषित किया जा सकता है। इस चर्चा के लिए, ढेर के बारे में सोचें स्मृति की एक असभ्य ब्लॉब के रूप में। स्टैक के विपरीत, जो आपके द्वारा दर्ज की जाने वाली आवश्यक स्मृति को स्वचालित रूप से आवंटित और डी-आवंटित करता है, आपको मैन्युअल रूप से आरक्षित और मुक्त ढेर मेमोरी चाहिए।

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

एक बार जब आप इसके साथ काम कर लें तो हेप ऑब्जेक्ट को मुक्त करना आपकी ज़िम्मेदारी है। delete कीवर्ड के साथ आप मुफ्त ढेर ऑब्जेक्ट्स। एक ढेर ऑब्जेक्ट पर विनाशक तब तक नहीं बुलाया जाता जब तक आप ऑब्जेक्ट को मुक्त नहीं करते।

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

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

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

यहाँ ढेर पर सामान बनाने का एक उदाहरण है, और जड़ सूचक दायरे से बाहर जा रहा है:

if (myCondition) { 
    Node* list_1 = new Node (3); 
    Node* list_2 = new Node (4); 
    Node* list_3 = new Node (5); 

    list_1->next = list_2; 
    list_2->next = list_3; 
    list_3->next = null; 
} 
// The list still exists 
// However list_1 just went out of scope 
// So the list is "marooned" as a memory leak 
+0

इनपुट के लिए धन्यवाद। तो मेरा अंतिम सवाल यह होगा कि (यदि सूची_1 में विनाशक था) तो विनाशक को जल्द ही बुलाया जाएगा ... list_1-> अगला = list_2; ... निष्पादित किया जाता है? –

+0

यह आपके अन्य अनुवर्ती से थोड़ा अलग है, इसलिए मैं दोनों का जवाब दूंगा। जवाब नहीं है, क्योंकि आप यहां जो कुछ भी कर रहे हैं वह आवंटित नोड को इंगित करने के लिए 'अगला' फ़ील्ड सेट कर रहा है - कुछ भी गुंजाइश से बाहर नहीं हुआ है। लेकिन यहां तक ​​कि यदि कुछ गुंजाइश से बाहर निकलता है, तो कोई विनाशक नहीं कहा जाएगा, क्योंकि यह कुछ संकेतक होगा (आपके मुख्य प्रश्न पर टिप्पणी अनुवर्ती देखें।) –

+0

नोट, वैसे, कि स्टैक पर बनाई गई वस्तु ** होगी ** इसका विनाशक कहलाता है जब यह गुंजाइश से बाहर हो जाता है। –

5
{ //scope is defined by the curly braces 
    std::vector<int> vec; 
} 
// vec is out of scope here! 
vec.push_back(15); 
1

जब यह गुंजाइश है कि यह :)

आपका प्रश्न के रूप में यह खड़ा में घोषित किया गया था छोड़ देता है कार्यान्वयन देखे बिना जवाबदेह नहीं है। यह नीचे आता है जहां आप इस नोड घोषित करते हैं।

void Foo() 
{ 
    int i = 10; 

    { 
     int j = 20; 
    } // j is out of scope 

} // i is out of scope 
2

"दायरे से बाहर" एक लक्षणालंकार है: के रूप में में, नाम या एक अवधारणा के शब्दावली का उपयोग निकट से संबंधित कुछ लेकिन अलग के बारे में बात करने के लिए।

सी ++ में एक गुंजाइश प्रोग्राम टेक्स्ट का एक स्थिर क्षेत्र है, और इसलिए कुछ भी "दायरे से बाहर", सचमुच लिया गया है, जिसका अर्थ भौतिक रूप से पाठ के क्षेत्र से बाहर है। उदाहरण के लिए, { int x; } int y;: y की घोषणा उस दायरे से बाहर है जिसमें x दिखाई दे रहा है।

मेटोनमी "गुंजाइश से बाहर निकलने" का विचार इस विचार को व्यक्त करने के लिए किया जाता है कि कुछ गुंजाइश से जुड़े पर्यावरण की गतिशील सक्रियण/तत्कालता समाप्त हो रही है। और इसलिए उस दायरे में परिभाषित चर दूर जा रहे हैं (इस प्रकार "दायरे से बाहर")।

वास्तव में "दायरे से बाहर" क्या चला गया है, निर्देशक सूचक है, इसलिए बोलना; कार्यक्रम का मूल्यांकन अब एक ऐसे क्षेत्र में हो रहा है जिसकी कोई दृश्यता नहीं है। लेकिन एक गुंजाइश में सब कुछ नहीं चला जाता है! अगली बार गुंजाइश दर्ज होने पर स्टेटिक वैरिएबल अभी भी होंगे।

"दायरे से बाहर जाना" बहुत सटीक नहीं है, लेकिन छोटा और हर कोई इसका अर्थ समझता है।

2

किसी ऑब्जेक्ट को फ़ंक्शन के अंदर घोषित किया गया है (या फ़ंक्शंस के अंदर कुछ घुंघराले-ब्रेस-ब्रैकेट किए गए संरचनाओं के अंदर) निष्पादन कोड के उस हिस्से को छोड़ देता है।

void some_func() { 
    std::string x("Hello!"); 
    // x is in scope here 
} 
// But as soon as some_func returns, x is out of scope 

यह केवल स्टैक पर घोषित सामान पर लागू होता है, तो यह थोड़ा के बाद से सूची नोड्स आमतौर पर new साथ ढेर पर instantiated किया जाएगा, अकेले लिंक्ड सूचियों से कोई लेना देना नहीं है।

इस उदाहरण में, सूचकnew द्वारा लौटाए गए क्षेत्र से बाहर जाना होगा जब समारोह बाहर निकलता है, लेकिन कुछ भी नोड खुद का क्या होगा:

void make_a_node() { 
    Node* p = new Node; 
} // Oh noes a memory leak! 
+0

यदि नोड क्लास में एक विनाशक लागू किया गया था, तो नोड को संदर्भित किया जा रहा है, जिसे विनाशक कहते हैं, पल पी गुंजाइश से बाहर निकलता है? –

+0

नहीं। मेरे पहले उदाहरण में, हालांकि, std :: string destructor * x को कॉल किया जाएगा जब एक्स गुंजाइश छोड़ देता है। दूसरे उदाहरण में, जो गुंजाइश छोड़ रहा है वह नोड नहीं बल्कि नोड * है, और पॉइंटर्स के पास स्वयं विनाशक नहीं हैं। – DSimon

+0

लेकिन यदि कच्चे सूचक के बजाय आपने 'std :: unique_ptr पी = नया नोड का उपयोग किया; 'नोड ऑब्जेक्ट का विनाशक बाहर निकलने पर बुलाया जाएगा, जब' p' गुंजाइश से बाहर हो जाता है .. – d7samurai