2010-02-27 12 views
6

मैं ऐसा करते हैं तो:बिल्ट-इन डेटा प्रकारों और उपयोगकर्ता परिभाषित लोगों के बीच अंतर को कैसे हटाता है?

// (1.) 
int* p = new int; 
//...do something 
delete p; 

// (2.) 
class sample 
{ 
public: 
sample(){} 
~sample(){} 
}; 
sample* pObj = new sample; 
//...do something 
delete pObj; 

तो कैसे सी ++ संकलक है कि वस्तु निम्नलिखित पता है delete में निर्मित डेटा प्रकार या एक वर्ग वस्तु है?

मेरे अन्य प्रश्न है कि अगर मैं int की की एक सरणी के लिए सूचक new और फिर मैं delete [] तो कैसे संकलक स्मृति ब्लॉक के आकार पता है डी-आवंटित करने के लिए है?

उत्तर

4
  1. संकलक के प्रकार जानता उठाई-पर आपत्ति है क्योंकि यह सूचक के प्रकार जानता है:

    • p एक int* है, इसलिए उठाई-पर आपत्ति एक int हो जाएगा।
    • pObjsample* है, इसलिए इंगित करने वाली वस्तु sample होगी।
  2. संकलक अपने int* p अंक अगर एक भी int वस्तु करने के लिए या एक सरणी (int[N]) पता नहीं है। यही कारण है कि आप को के बजाय delete का उपयोग करना याद रखना चाहिए।

    स्मृति ब्लॉक का आकार डी-आवंटित करने के लिए और सबसे महत्वपूर्ण बात यह है कि नष्ट करने के लिए वस्तुओं की संख्या ज्ञात है, क्योंकि new[] उन्हें कहीं स्टोर करता है, और delete[] जानता है कि इन मानों को पुनर्प्राप्त करने के लिए कहां से प्राप्त किया जाए। This question from C++ FAQ Litenew[] और delete[] को लागू करने के लिए दो सामान्य तकनीकों को दिखाता है।

4

यह आपके द्वारा पारित पॉइंटर के प्रकार के कारण उनके बीच का अंतर जानता है: यह आपके द्वारा आवंटित किए गए एक अलग सूचक प्रकार को पारित करने के लिए अपरिभाषित व्यवहार है (सिवाय इसके कि आप बेस क्लास में पॉइंटर पास कर सकते हैं, अगर विनाशक virtual है, ज़ाहिर है)।

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

उदाहरण के लिए यह आवंटित बफर से पहले तत्वों की गिनती को स्टोर कर सकता है। मानक स्पष्ट रूप से संकलक को सरणी आवंटन के मामले में आवंटन फ़ंक्शन (operator new[]) पर एक अलग अनुरोध आकार को पारित करने की अनुमति देता है - इसका उपयोग संकलक द्वारा गणना में किया जा सकता है और आकार के अनुसार new अभिव्यक्ति द्वारा दिए गए पते को ऑफ़सेट कर सकता है उस काउंटर का।

1

ऐसा नहीं है!

सभी delete क्या यह है कि यह प्रकार के विनाशक को आमंत्रित करता है, जो कि आदिम प्रकारों के मामले में "कोई कार्रवाई नहीं" है। फिर, यह सूचक को ::operator delete (या यदि आप चाहें तो अधिभारित संस्करण) तक पास करता है, और ऑपरेटर स्मृति (एक मेमोरी प्रबंधक समस्या) वापस देता है। यानी यदि आप चाहें तो सी ++ में आसानी से अपना खुद का मेमोरी मैनेजर लिख सकते हैं, भाषा डिफ़ॉल्ट रूप से एक प्रदान करती है!

1
  1. संकलक जानता वस्तु के प्रकार हटाया जा रहा है और आप सही परिणाम प्राप्त करने के लिए अलग-अलग कोड लिखते हैं:
    • पी हटाना रन टाइम किसी पूर्णांक के आकार के साथ हटाना कॉल कर सकते हैं।
    • हटा pObj कॉल कर सकते हैं pObj-> ~ नमूना() पहले, तो नमूने का आकार
  2. मैं सरणियों के साथ लगता है के साथ हटाने के लिए, वहाँ, सरणी के आकार के लिए एक छिपा मूल्य है, इसलिए यह हो सकता है कि एक सर में पूरी सरणी हटा दी गई है।
1

तो कैसे सी ++ संकलक हटाने में निर्मित डेटा प्रकार या एक वर्ग वस्तु है निम्नलिखित है कि वस्तु में पता है?

क्योंकि संकलन समय पर संकलक प्रत्येक ऑब्जेक्ट के प्रकार और पौधों को एप्रोप्रेट कोड ट्रैक करता है।

मेरा दूसरा सवाल यह है कि यदि मैं int की एक सरणी के लिए एक पॉइंटर नया करता हूं और फिर मैं हटा देता हूं [] तो संकलक को स्मृति आवंटन के आकार को आवंटित करने के लिए कैसे पता चलता है?

ऐसा नहीं है।इसे रनटाइम सिस्टम द्वारा ट्रैक रखा जाता है।
जब आप गतिशील रूप से एक सरणी आवंटित करते हैं तो रनटाइम लाइब्रेरी ऑब्जेक्ट के आकार को ऑब्जेक्ट के साथ जोड़ती है, इस प्रकार जब इसे हटा दिया जाता है तो यह आकार (संबंधित मान को देखकर) जानता है।

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

0

पहले (गैर सरणी) प्रश्न के भाग के लिए, यह दर्शाता है कि संकलक सूचक प्रकार के आधार पर बाइट्स की उपयुक्त संख्या को डी-आवंटित करने के लिए कोड सम्मिलित करता है ऊपर जवाब, काफी प्रदान नहीं करते मेरे लिए स्पष्ट उत्तर ... डिलीट ऑपरेटर 1) लागू होने पर एक विनाशक को कॉल करता है और फिर 2) "ऑपरेटर डिलीट()" फ़ंक्शन को कॉल करता है ... यह ऑपरेटर डिलीट करता है जो वास्तव में डी-आवंटित करता है। मैं भाग (1), यानी भाग में भूमिका निभाते हुए कंपाइलर-जेनरेट कोड देख सकता हूं। विनाशक का गंतव्य पता डाला जाना चाहिए। लेकिन कुछ हिस्सों में (2), यह एक पूर्व-मौजूदा लाइब्रेरी फ़ंक्शन है जो डी-आवंटन को संभालने में सक्षम है, तो यह डेटा के आकार को कैसे जानेंगे? ग्लोबल ऑपरेटर डिलीट - जो, मेरा मानना ​​है कि सभी मामलों में इसका उपयोग तब तक किया जाता है जब तक कि क्लास-सदस्य/ओवरलोडेड-ग्लोबल वर्जन प्रोग्रामर द्वारा परिभाषित नहीं किया जाता है - डेटा की शुरुआत के बारे में केवल एक शून्य * तर्क स्वीकार करता है, इसलिए यह कर सकता है डेटा आकार भी पारित नहीं किया जाएगा। मैंने संकलक-जेनरेट किए गए कोड विचार को इंगित करने वाली चीजों को पढ़ा है, साथ ही चीजों को यह भी सुझाव दिया है कि वैश्विक ऑपरेटर गैर-सरणी के लिए हटा देता है, बस मुफ्त(), यानी उपयोग करता है। यह डेटा आकार को पॉइंटर प्रकार से नहीं जानता है, लेकिन डेटा से पहले कुछ बाइट्स देखकर, जहां आकार को नए/मॉलोक द्वारा रखा जाएगा। उत्तरार्द्ध एकमात्र समाधान है जो मुझे समझ में आता है, लेकिन शायद कोई मुझे अलग-अलग ज्ञान दे सकता है ...

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