2009-05-07 14 views
8

मैं किसी वर्ग के लिए सूचक है। चलो कहते हैं, उदाहरण के लिए, सूचक है:डिलीट होने पर सी ++ पॉइंटर को क्या लिखा जाता है यह निर्धारित करता है?

0x24083094 

कि सूचक अंक के लिए:

0x03ac9184 

कौन सा मेरी कक्षा का आभासी समारोह टेबल है। मेरे लिए उसका मतलब बनता है। विंडबग में, सब ठीक दिखता है।

मेरे द्वारा हटाए जाने सूचक कहा। अब 0x24083094 पर है:

0x604751f8 

लेकिन यह कुछ यादृच्छिक कचरा, कि पता वहाँ हर बार में डाल दिया जाता है नहीं है, यह लगातार 0x604751f8 है! इतना है कि मैं वास्तव में उस पते का उपयोग यह निर्धारित करने के लिए कर सकता हूं कि क्या यह सूचक हटा दिया गया था, मेरे आवेदन के निष्पादन के बीच!

लेकिन क्यों? यह कैसे निर्धारित करता है कि 0x604751f8 वहां लिखा जाना चाहिए?

रिकॉर्ड के लिए, मैं खिड़कियों का उपयोग कर रहा, दृश्य स्टूडियो के तहत निर्माण 2003

मैं जानता हूँ कि मैं, कि मूल्य स्थापित किया जा रहा पर भरोसा नहीं कर सकते भले ही यह सुसंगत प्रतीत होता है, लेकिन मैं पर भरोसा कर सकते यह अलग है? अर्थात, और 0x03ac91840x24083094 पर नहीं हो सकता है अगर सूचक, हटा दी जाती है ना? वहां क्या रखा जाता है? यह कुछ भी हो सकता है, लेकिन 0x03ac9184 निश्चित रूप से वहां नहीं होगा (या फिर मैं अभी भी विधियों को कॉल कर सकता हूं, क्योंकि यह वर्चुअल फ़ंक्शन टेबल है)। क्या मैं सही हू?

मुझे लगता है कि मैं इस सवाल का जवाब है। हटाए जाने के बाद कुछ भी भरोसा नहीं कर सकता। शायद कुछ पृष्ठभूमि लोगों को यह देखने में मदद करेगी कि मैं कहां से आ रहा हूं। अनिवार्य रूप से, मैं एक बग को ठीक करने की कोशिश कर रहा हूं जहां मेरे नीचे से एक सूचक हटा दिया जाता है। यह एक लंबी कहानी है, मैं विवरण में नहीं जाऊंगा।

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

हालांकि, दिलचस्प बात यह है कि हमारे कोड में हम एक वर्ग 'BogusObject' कहा जाता है कि अनिवार्य रूप से एक ट्रे लोगों की है कि गलती से भिन्नता वस्तुओं मुक्त कर दिया पकड़ने के रूप में कार्य किया है। असल में, हम अपने स्वयं के डिलीट फ़ंक्शंस को हुक करते हैं और किसी भी मुक्त वर्ग के vtable में BogusObject क्लास को बाश करते हैं।

फिर अगर कोई कुछ कहता है तो उन्हें "हे, कुछ गलत दोस्त" के प्रभाव के बारे में कुछ कहने का एक अच्छा संदेश मिलता है। यह मेरे मामले में हो रहा है। I.e, 0x604751f8+(someoffset) BogusObject क्लास के अंदर है। लेकिन अब हम BogusObject का उपयोग नहीं करते हैं! यह सचमुच कहीं भी स्थापित नहीं है (अगर मैं पूरी तरह से BogusObject क्लास को हटा देता हूं तो भी ठीक से लिंक करता है), और फिर भी मैं अच्छा संदेश प्राप्त कर रहा हूं कि कुछ गलत है! लेकिन अब मैं राय मान रहा हूं कि यह एक संयोग है।

कुछ कारणों से रनटाइम उस पॉइंटर में 0x604751f8 मान डाल रहा है, और यह उस वर्ग के अनुरूप होता है जिसका उद्देश्य इस तरह की स्थितियों को पकड़ने का उद्देश्य है!

+1

आप अपने सूचक (0x24083094) पर डेटा ब्रेकपॉइंट क्यों सेट नहीं करते हैं और देखते हैं कि 0x604751f8 कब लिखा जाता है? जब डीबगर टूट जाता है, तो यह देखने के लिए स्टैक को क्रॉल करें कि आपको किसने बुलाया और कहां से आया था। –

+0

हाँ मैंने ऐसा किया। यह MyModule से लौटने के बाद बदल जाता है! MyClass :: 'वेक्टर हटाने वाले विनाशक '। जब हटाया जाता है और जब यह बदलता है तो मैंने प्रत्येक पंक्ति में कदम रखा है। असल में, मेरे पास एक विंडबग लॉग है जो इसे दिखा रहा है, इसमें कुछ डीटी बदल रहे हैं। हालांकि, इसमें बहुत सारी कंपनी सामग्री है इसलिए मुझे साझा करने से पहले इसे साफ़ करने की आवश्यकता होगी। – pj4533

उत्तर

16

मानक में कुछ भी निर्धारित नहीं करता कि वहां क्या लिखा जाता है।विजुअल स्टूडियो (कम से कम डीबग मोड में) अक्सर बग को पकड़ने में मदद के लिए सभी जगह पर भावुक मूल्य लिखेंगे।

यह मान ऐसा कुछ नहीं है जिस पर आप भरोसा कर सकते हैं, लेकिन यदि आपको कभी भी यह प्रोग्राम आपके प्रोग्राम में रहस्यमय तरीके से पॉप-अप करने लगता है, तो आप मान सकते हैं कि कहीं भी आप हटाए गए स्मृति का संदर्भ दे रहे हैं। एक कंपाइलर के तहत मूल्यों की सूची के लिए this answer देखें।

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

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

संपादित करें: आप हटाए जाने के बाद उस मूल्य को बदलने पर भी भरोसा नहीं कर सकते। ऐसा कुछ भी नहीं है जो कहता है कि एक कंपाइलर को हटाने पर डेटा को संशोधित करने की आवश्यकता है।

+0

हाँ मैं फीफ़ी के बारे में जानता हूं और क्या नहीं। लेकिन इसके लिए मेरे मामले में स्थिरता हमेशा उस स्थान पर 0x604751f8 डालती है? – pj4533

+3

0x604751f8 किसी चीज़ के लिए पॉइंटर होने की संभावना है (शायद एक और मुफ्त ब्लॉक)। लेकिन यह बिटफ्लैग का एक समूह या हस्ताक्षर –

+5

या कचरा भी हो सकता है (ऐसा कुछ भी नहीं है जो कहता है कि कचरा संगत नहीं हो सकता है)। –

2

बस पॉइंटर के लिए डिलीट ऑपरेटर को कॉल करने का मतलब यह नहीं है कि "हटाई गई" मेमोरी साफ़ हो जाएगी। यह केवल हटाए गए ऑब्जेक्ट के विनाशक को कॉल करेगा और आवंटित ढेर मेमोरी को हटाए जाने के रूप में चिह्नित करेगा। (यह डिलीट ऑपरेटर का डिफ़ॉल्ट व्यवहार है)।

यदि आपको हटाने पर स्मृति सामग्री को साफ़ करने की आवश्यकता है, तो आपको डिलीट ऑपरेटर को ओवरराइड करने की आवश्यकता है।

+0

ठीक है, लेकिन कुछ और हो रहा है, क्योंकि स्मृति बदलती है। मैं समझता हूं कि यह इसे साफ़ नहीं करता है .... लेकिन यह लगातार 0x604751f8 बनाता है। क्यूं कर? – pj4533

+0

क्या आप हटाए गए कथन के बाद सही जांच कर रहे हैं? उस स्थिति में, या तो विनाशक सूचक को बदलता है या सूचक दूसरे धागे से बदल जाता है। – Jonatan

+0

डीबग मोड में संकलित होने पर यह बदलता है।AFAIK आवंटन रद्द करने कार्यों के पीछे "निशान" स्मृति के रूप में मुक्त करने के लिए deallocated स्मृति की सामग्री को बदल, डिबग प्रयोजनों के लिए हटा दें। लेकिन रिलीज लक्ष्य में नहीं, प्रदर्शन कारणों से ... –

4

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

आप जिस विशेष मूल्य को देख रहे हैं उसका मतलब है? लगभग कुछ भी हो सकता है।

+0

इससे भी अधिक, यह शायद एक ढेर रिकॉर्ड संरचना के बीच में गलत संरेखित पहुँच है। – Joshua

2

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

2

लगभग निश्चित रूप से उस मूल्य के लिए एक विशिष्ट आंतरिक अर्थ है जो हर बार जब आप वस्तु को हटाते हैं।

हालांकि, यह विजुअल सी ++ के अगले संस्करण के साथ बदल सकता है, और निश्चित रूप से अन्य विक्रेताओं के कंपाइलरों पर अलग होगा।

तथ्य यह है कि जब भी आप ऑब्जेक्ट किसी ऑब्जेक्ट को हटाते हैं, तो यह उपयोगी होता है कुछ भी उपयोगी नहीं है। न ही यह भी संभावित रूप से उपयोगी हो सकता है। मान लीजिए कि आपको इसका लाभ उठाने का कोई तरीका मिल गया है, ऐसा करने के लिए यह एक भयानक हैक होगा, और आप अंततः इसे पछतावा करेंगे।

इसे अपने दिमाग से बाहर रखने का प्रयास करें!

+0

यह एक डिबगिंग सहायता के रूप में उपयोगी हो सकता है। – florin

+0

@florin, जब तक आप सांख्यिकीय डिबगिंग एक बुरा विचार है कि पसंद है। – Joshua

2

जैसा कि माइकल बुर ने पहले कहा था, स्मृति वापस मुफ्त स्टोर में जाती है। कुछ मुफ्त स्टोर को लिंक्ड सूचियों के रूप में कार्यान्वित किया जाता है, -> अगला बफर मुफ्त बफर की शुरुआत में रखा जाता है। यह संभव है कि आप जिस जादू संख्या को देख रहे हैं (0x604751f8) 'सूची का अंत' गार्ड बनें।आप निम्न प्रयोग करके जांच कर सकते हैं:

Foo* f = new Foo(); 
Bar* b = new Bar(); 

// make a note of the values of f and b _pointers_ 

delete b; // check that b points now to 0x604751f8 
delete f; // check that f points now to 0x604751f8 

// now check that does b point to; it might point to f! 

हमें बताएं कि आपको क्या मिल रहा है!

2

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

ध्यान दें कि यह व्यवहार संकलक के क्रम सी ++ समर्थन का एक आंतरिक कार्यान्वयन विस्तार, इसलिए अन्य compilers (या एक ही संकलक के भविष्य के संस्करणों) कुछ पूरी तरह से अलग कर सकता है। लेकिन इस 'आधार वर्ग के लिए vtable बदलने और फोन आधार वर्ग नाशक' काफी आम है और वापस सी ++

2

के मूल cfront कार्यान्वयन कार्यक्रम तुम्हें कुछ बताना कोशिश कर रहा है की है। एक तिथि, एक टेलीफोन नंबर, जो जानता है?

अब गंभीरता से, इस निर्दिष्ट नहीं है, पूरी तरह से कार्यान्वयन पर निर्भर, और निश्चित रूप delete के बाद कि संकेतक भिन्नता की कोशिश की अपरिभाषित व्यवहार करने के लिए नेतृत्व करेंगे। तो, संक्षेप में, कौन परवाह करता है?

2

नहीं, आप पर यह स्थापित किया जा रहा भरोसा नहीं कर सकते। आप इसे अलग होने पर भी भरोसा नहीं कर सकते हैं।

MS-DOS ढेर प्रबंधक अक्सर malloc के लिए अगली कॉल जब तक मुक्त कर दिया स्मृति का उपयोग की अनुमति दी। उस युग में नया और हटाएं जिसे मॉलोक और फ्री कहा जाता है।

इन दिनों, सबसे ढेर प्रबंधकों ओएस, आप भी यह पठनीय होने पर भरोसा नहीं कर सकते, जिसका अर्थ है करने के लिए स्मृति लौटने के बारे में उचित कर रहे हैं! यहां तक ​​कि एक भी जो इसे अभी भी अनुमति देता है (glibc में एक bwd-compat मोड है जो इसे अनुमति देता है) आप थ्रेड-रेस स्थितियों के अधीन हैं।

इसके अलावा, हटाना शून्य करने के लिए सूचक को बदलने के लिए करता है, तो यह एक lvalue है अनुमति दी है।

एक बार जब आप डिलीट करते हैं, तो पॉइंटर को डिफ्रेंस करने के बारे में भी सोचें।

0

आपके पास विजुअल स्टूडियो में सीआरटी स्रोत कोड तक पहुंच है। आप एक नज़र डाल सकते हैं। मैंने एक बार एक बग को बेहतर ढंग से समझने के लिए किया था।

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