2009-06-17 7 views
7
class object 
{ 
    public: 
    void check() 
    { 
     std::cout<<"I am doing ok..."<<std::endl; 
    } 
}; 

int main() 
{ 
    object *p = new object; 
    p->check(); 
    delete p; 
    p->check(); 
    delete p; 
    p->check(); 
} 

संपादित: गुरुओं, मैं "या यह क्रैश हो सकता है नहीं हो सकता है" बयान के कई से उलझन में हूँ .. क्यों नहीं है वहाँ कहने के लिए एक मानक है, हम स्मृति का एक ब्लॉक के साथ यह कैसे सौदा हटा दी जाती है कि 'डिलीवरी ऑपरेटर' का उपयोग कर ..? कोई इनपुट?क्यों कोड का नीचे का टुकड़ा क्रैश नहीं हो रहा है, हालांकि मैंने ऑब्जेक्ट को हटा दिया है?

+0

गुरु, मैं कई कथनों से उलझन में हूं "यह क्रैश हो सकता है या नहीं हो सकता है" .. कहने का कोई मानक क्यों नहीं है, यह हम 'डिलीट ऑपरेटर' का उपयोग करके हटाए गए स्मृति के ब्लॉक से कैसे निपटते हैं .. ? कोई इनपुट? – Warrior

+2

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

उत्तर

10

क्या यह वास्तव में की तरह के बाद संकलक अपनी तरह से किया गया है लग रहा है कुछ इस तरह है क्योंकि:

object::check(object* this) 
{ 
    // do stuff without using this 
} 

int main() 
{   
    object *p = new object; 
    object::check(p); 
    delete p; 
    object::check(p); 
    delete p; 
    object::check(p); 
} 

आप के बाद से इस "स्पर्श नहीं कर रहे", आप वास्तव में किसी भी खराब स्मृति का उपयोग नहीं करते हैं।

हालांकि, पी दो बार को हटाने के लिए एक दुर्घटना का कारण करने के लिए सक्षम होना चाहिए:

http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.2

+1

संभावित रूप से दुर्घटनाग्रस्त होने के कारण 2x हटाने के संबंध में ... हाँ, यही कारण है कि मैं आमतौर पर हटाने के बाद "पी" को 0 पर सेट करता हूं ... ए) इसलिए मुझे पता है कि यह किसी ऑब्जेक्ट को इंगित नहीं करता है और बी) क्योंकि यह सुरक्षित है एक शून्य सूचक पर कॉल हटाएं। – Dan

+0

मैंने देखा है कि कई कोडेबेस मैंने इस कारण से "# परिभाषित SAFE_DELETE (x) x, x = NULL" मैक्रो, या बेहतर अभी तक टेम्पलेट हटा दिया है। यह उन कुछ स्थानों में से एक है जहां मुझे अल्पविराम ऑपरेटर पसंद है - जहां तक ​​मेरा संबंध है, हटाएं और एनयूएलएल असाइनमेंट को अधिकांश मामलों में एक ही कथन के "संबंधित" होना चाहिए। – leander

7

क्योंकि फ़ंक्शन ऑब्जेक्ट के सदस्य डेटा या this पॉइंटर के साथ कुछ भी नहीं कर रहा है।

यह self तर्क के रूप में गलत सूचक के साथ एक समारोह

void check(object *self) 
{ 
    std::cout<<"I am doing ok..."<<std::endl; 
} 

बुला की तरह है।

हालांकि एक डबल डिलीट है, जो कुछ वातावरण में क्रैश हो सकता है।

+1

यह उससे भी मजेदार है। यह संकलित करता है और अच्छी तरह से चलता है: # शामिल नामस्थान std का उपयोग कर; कक्षा वस्तु { सार्वजनिक: शून्य जांच() { cout << "मैं ठीक कर रहा हूं ..." << endl; } }; int मुख्य() { ऑब्जेक्ट * पी = (ऑब्जेक्ट *) 0; पी-> चेक(); वापसी 0; } $ g ++ -o t t.cc $ $ ./t मैं ठीक कर रहा हूं ... $ :) आपको वास्तव में इस विधि को कॉल करने के लिए कोई ऑब्जेक्ट नहीं है! चीयर्स, एच। – haavee

+0

ओउ प्रिय, लेट गड़बड़ है। स्वतंत्र उत्तर के रूप में repost होगा ... – haavee

+2

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

0

मुझे लगता है कि यह पर्यावरण (प्लेटफार्म/कंपाइलर) पर निर्भर करता है ...
यह कम से कम अप्रत्याशित व्यवहार देता है। मुझे लगता है कि तुम भाग्यशाली है कि यह अपने मामले ;-) में दुर्घटना नहीं करता है

7

हटाएं केवल स्मृति deallocates और इसे वापस ढेर करने के लिए उपलब्ध बनाता है।

हटाए जाने के बाद पॉइंटर का मान अपरिभाषित है, इसलिए यह क्रैश हो सकता है।

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

+0

आप अभी भी सूचक का उपयोग कर सकते हैं। एनयूएलएल के लिए एक चेक किया जाना है, लेकिन मुझे लगता है कि यही मतलब है। – ralphtheninja

+2

एक सच्ची स्टेटमेंट लेकिन इस "मुद्दे" के लिए पूरी तरह से अनुपयोगी है। NULL को सेटिंग पॉइंटर का उल्लेख करने के लिए – haavee

+0

+1। जब भी डिबगिंग हो तो बहुत बढ़िया क्योंकि हटाए गए पॉइंटर्स ऐसा नहीं दिखते कि वे अभी भी वैध हो सकते हैं। – markh44

2

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

0

दूसरों ने जो कहा है उससे थोड़ा जोड़ने के लिए, चेक() विधि के अंदर अपनी कक्षा के सदस्य चर का उपयोग करने का प्रयास करें और फिर देखें कि क्या होता है।

कक्षाओं के मामले में फ़ंक्शन कॉलिंग सामान्य फ़ंक्शन कॉलिंग के समान है जो एक छोटे से अंतर को छोड़कर है। तर्क दोनों मामलों में ढेर पर धकेल दिए जाते हैं लेकिन किसी ऑब्जेक्ट के फ़ंक्शन कॉल के मामले में, 'यह' को पहले तर्क के रूप में स्टैक पर धक्का दिया जाता है। सदस्य चर को एक्सेस करने के लिए यह 'यह' फ़ंक्शन के अंदर उपयोग किया जाता है। चूंकि आप किसी भी सदस्य चर का उपयोग नहीं कर रहे हैं, यह काम कर रहा है। और हां, यह काम कर सकता है भले ही आप सदस्य चर का उपयोग करते हैं लेकिन आपको अप्रत्याशित व्यवहार मिलेगा क्योंकि संकलक 'पी' को आवंटित स्मृति का उपयोग करने के लिए स्वतंत्र है। जैसे ही संकलक उस स्मृति का उपयोग करेगा, आप क्रैश हो जाना शुरू कर देंगे। उदाहरण के लिए, यदि आप 'पी' का उपयोग करने से पहले हटाने के बाद और चर को घोषित करते हैं, तो यह क्रैश हो सकता है।

संपादित करें: इसके अलावा, यदि आपकी विधि किसी भी सदस्य चर का उपयोग नहीं कर रही है, तो यह एक स्थिर विधि होने के लिए एक निश्चित उम्मीदवार है।

+0

ब्रो मैंने इस तरह के कोड को बदल दिया है, फिर भी यह क्रैश नहीं होता है: क्लास ऑब्जेक्ट { int p; सार्वजनिक: ऑब्जेक्ट() { पी = 100; } शून्य चेक() { std :: cout << "p =" << p << std :: endl; std :: cout << "मैं ठीक कर रहा हूं ..." << std :: endl; } }; >> ./test पी = 100 मैं ठीक कर रहा हूँ ... पी = 100 मैं ठीक कर रहा हूँ ... पी = 100 मैं ठीक कर रहा हूँ ... – Warrior

+0

जैसा कि मैंने पहले बताया गया है, को हटाने 'पी' का मतलब है कि संकलक के लिए स्मृति का उपयोग करने के लिए स्वतंत्र है। आंतरिक रूप से, जिस स्थान पर पॉइंटर 'पी' इंगित कर रहा है वह अभी भी एक मान्य पता है। 'पी' का पुन: उपयोग करने से पहले कुछ और पॉइंटर चर घोषित करने का प्रयास करें और यह क्रैश हो सकता है। यह आपको अप्रत्याशित व्यवहार देगा। कोई भी आपको बता सकता है कि जब यह बिल्कुल दुर्घटनाग्रस्त हो जाएगा। – Aamir

5

आप नहीं के बराबर संकेत के साथ एक ही है, बस जब तक आप वर्ग उदाहरण के राज्य का उपयोग कभी नहीं कर सकते हैं:

class object 
{ 
    public: 
    void check() 
    { 
     std::cout<<"I am doing ok..."<<std::endl; 
    } 
}; 

int main() 
{ 
    object *p = 0; 
    p->check(); 
} 
5

यह उससे भी मजेदार है। यह & रन अच्छी तरह से संकलित:

#include <iostream> 
using namespace std; 
class object { 
    public: 
     void check() { 
      cout << "I am doing ok..." << endl; 
     } 
}; 

int main() { 
    object *p = (object*)0; 
    p->check(); 
    return 0; 
} 

खोल करने के लिए पर:

 
$ g++ -o t t.cc 
$ ./t 
I am doing ok... 
$ 

:) आप वास्तव में एक वस्तु इस विधि कॉल करने के लिए नहीं है! चियर्स, ज

1

1) जीसीसी 4.0.1 के साथ संकलक पर निर्भर करता है, मैक ओएस पर:

g++ -Wall -g -c main.cpp -o main.o 
g++ -o x main.o 
./x 
I am doing ok ... 
I am doing ok ... 
x(5857) malloc: *** error for object 0x100150: double free 
*** set a breakpoint in malloc_error_break to debug 
I am doing ok ... 

डबल मुक्त खड़ी कर रहा है समस्याओं।

2) आम तौर पर हटाए गए पॉइंटर को हटाने से पहले परिभाषित नहीं किया गया है, आपको हमेशा पॉइंटर को हटाने के बाद 0 पर सेट करना चाहिए, पॉइंटर पर मूल्य 0 के साथ कॉल करने की अनुमति है।

3) कारण यह स्ट्रिंग को मुद्रित करने का कारण यह है कि सूचक अभी भी स्मृति को इंगित करता है जिसे अब मुक्त किया गया था, लेकिन मुझे लगता है कि केवल सूचक को पुनः दावा किया गया है। पुन: उपयोग के लिए मुफ्त पूल में लौट आया, स्मृति को अधिलेखित या शून्य नहीं किया गया है, इसलिए यदि आप पॉइंटर को अस्वीकार करते हैं तो आपको अभी भी मूल मान मिलते हैं, जब तक कि इस दौरान स्मृति का पुन: उपयोग नहीं किया जाता है।

1

हटाएं पी को शून्य पर सेट नहीं करता है, इसलिए यह अभी भी स्मृति स्थान को इंगित करता है। यह नए/हटाए जाने के कार्यान्वयन पर निर्भर करता है लेकिन आम तौर पर किसी भी नए आवंटन के लिए उपलब्ध स्मृति के उस हिस्से को केवल अंक ही हटा देता है।

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

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