2009-08-20 11 views
5

मैं कुछ कॉलेजों के साथ बहस कर रहा था कि जब आप गतिशील रूप से आवंटित कक्षा में अपवाद फेंकते हैं तो क्या होता है। मुझे पता है कि मॉलोक को बुलाया जाता है, और फिर कक्षा के निर्माता। कन्स्ट्रक्टर कभी वापस नहीं आता है, तो मॉलोक के साथ क्या होता है?जब मैं अपवाद फेंकता हूं तो स्मृति जारी हो जाती है?

निम्नलिखित

class B 
{ 
    public: 
     B() 
     { 
      cout << "B::B()" << endl; 
      throw "B::exception"; 
     } 

     ~B() 
     { 
      cout << "B::~B()" << endl;   
     } 
}; 

void main() 
{ 
    B *o = 0; 
    try 
    { 
     o = new B; 
    } 

    catch(const char *) 
    { 
    cout << "ouch!" << endl; 
    } 
} 

malloced स्मृति 'ओ', यह रिसाव करता है तो क्या होता है पर विचार करें? क्या सीआरटी कन्स्ट्रक्टर के अपवाद को पकड़ता है और स्मृति को निष्क्रिय करता है?

चीयर्स रिच

+0

संक्षिप्त उत्तर: हां। विवरण के लिए Cătălin Pitiş उत्तर देखें। –

उत्तर

9

एक कॉल

को
new B(); 

दो बातों में निराकरण:

  • एक ऑपरेटर नई() (साथ आवंटन या तो वैश्विक एक या एक वर्ग विशेष से एक है, वाक्य रचना के साथ संभवतः एक नियुक्ति एक new (xxx) B())
  • कन्स्ट्रक्टर को कॉल करना।

यदि निर्माता फेंकता है, तो इसी ऑपरेटर डिलीट को बुलाया जाता है। वह मामला जहां संबंधित डिलीट प्लेसमेंट है, वह एकमात्र ऐसा मामला है जहां प्लेसमेंट डिलीट ऑपरेटर को वाक्यविन्यास :: ऑपरेटर डिलीट() के बिना बुलाया जाता है। delete x; या delete[] x; प्लेसमेंट डिलीट ऑपरेटर को कॉल न करें और उन्हें कॉल करने के लिए नए प्लेसमेंट के लिए कोई समान वाक्यविन्यास नहीं है।

ध्यान दें कि बी के विनाशक नहीं कहा जा सकता है, पहले से ही उपनिवेश (सदस्यों या बी और बी के आधार वर्ग) को ऑपरेटर हटाने के लिए कॉल से पहले नष्ट कर दिया जाएगा। जिसे कन्स्ट्रक्टर नहीं कहा जाता है वह बी

+0

महत्वपूर्ण परिशिष्ट: बी के लिए कन्स्ट्रक्टर नहीं चला था, उस प्रकार का कोई ऑब्जेक्ट कभी नहीं था। अगर अपवाद को ट्रिगर करने से पहले बी के निर्माता में नया() कहा जा रहा था, तो इसे * जारी नहीं किया जा रहा है - और अब आपके पास उस स्मृति में कोई सूचक नहीं है, इसलिए आप इसे हटा नहीं सकते हैं। * रचनाकारों में नए() से * हमेशा रहें। – DevSolar

+0

यदि आप आरएआईआई तकनीकों का उपयोग करते हैं (उदाहरण के लिए, std :: auto_ptr के साथ), कन्स्ट्रक्टर में नया() एक बड़ा सौदा नहीं है। –

+0

@DevSolar: सभी इस बात पर निर्भर करता है कि नया परिणाम कहां संग्रहीत किया जाता है। यदि यह एक स्मार्ट सूचक में है, तो कन्स्ट्रक्टर के लिए स्थानीय या कक्षा बी या उसके माता-पिता के सदस्य, उस वस्तु को नष्ट कर दिया जाएगा और बी के निर्माता के भीतर आवंटित स्मृति, लेकिन अपवाद को फेंकने से पहले मुक्त हो जाएगा। जाहिर है अगर आप नया फू() करते हैं; "बार" फेंक दें, स्मृति मुक्त नहीं होगी और फू को नष्ट नहीं किया जाएगा। एक निर्माता या अन्य जगहों में। मैं स्पष्ट करता हूं कि बी के विनाशक को बुलाया नहीं जाता है। – AProgrammer

6

एक अपवाद निर्माता से फेंका जाता है, स्मृति नया द्वारा आवंटित जारी किया गया है, लेकिन वर्ग बी के नाशक नहीं बुलाया जाता है।

+2

हां। बस अपने उत्तर के पूरक के लिए ... विनाशक के लिए एक अच्छा कारण नहीं कहा जा रहा है: वस्तु कभी नहीं बनाई गई थी। विनाशकों को केवल उन वस्तुओं के लिए बुलाया जाता है जो एक विशेष अवधि में मौजूद होते हैं। और वे मामले हैं जहां कन्स्ट्रक्टर सफलतापूर्वक पूरा हुआ। –

+1

हां, आप सही हैं। कन्स्ट्रक्टर सफलतापूर्वक निष्पादित होने के बाद ही एक वस्तु को बनाया जाता है (इसलिए विनाशकारी)। –

+0

नोट: किसी भी पूरी तरह से निर्मित सदस्यों और बेस क्लास के विनाशक को बुलाया जाता है। –

2

इस मामले में, आपकी ऑब्जेक्ट, ओ वास्तव में निर्मित नहीं होता है, और नए द्वारा आवंटित स्मृति मुक्त हो जाती है। इस प्रकार, विनाशक को बुलाया नहीं जाता है। तो आपको कॉल करने की आवश्यकता नहीं है:

delete o; 

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

यदि ऑब्जेक्ट बनाया गया है, तो आपने सफलतापूर्वक संसाधन प्राप्त कर लिया है। इसका मतलब है कि वस्तु के जीवन के लिए, आप संसाधन के मालिक हैं। जब वस्तु हटा दी जाती है, संसाधन जारी किया जाता है। यदि ऑब्जेक्ट कभी नहीं बनाया गया है, तो आपने संसाधन कभी हासिल नहीं किया है। विकिपीडिया देखें:

http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

+0

नतीजतन, अगर निर्माता ने अपवाद को ट्रिगर करने से पहले _some_ संसाधन अधिग्रहण कार्य किया है, तो यह है कि कन्स्ट्रक्टर का काम इससे पहले साफ हो जाए। – Stewart

1

सी ++ 2003 मानक 5.3 से।4/17 - नई:

ऊपर वर्णित वस्तु आरंभीकरण के किसी भी हिस्से में एक अपवाद और एक उपयुक्त आवंटन रद्द समारोह फेंक पाया जा सकता है के द्वारा समाप्त करता है, आवंटन रद्द करने समारोह स्मृति है जिसमें वस्तु किया जा रहा था मुक्त करने के लिए कहा जाता है बनाया गया, जिसके बाद अपवाद नई अभिव्यक्ति के संदर्भ में प्रचार जारी है। यदि कोई स्पष्ट मेल खाने वाला कार्य नहीं पाया जा सकता है, तो अपवाद का प्रचार करने से ऑब्जेक्ट की स्मृति को मुक्त नहीं किया जा सकता है। [नोट: यह उचित है जब आवंटित आवंटन समारोह स्मृति आवंटित नहीं करता है; अन्यथा, यह एक स्मृति रिसाव के परिणामस्वरूप होने की संभावना है। ]

तो वहाँ या रिसाव नहीं हो सकता - जहां वहाँ यह है कि क्या एक उपयुक्त deallocator पाया जा सकता है पर निर्भर करता है (जो आम तौर मामला है, जब तक कि ऑपरेटर नई/हटाने अधिरोहित किया गया है) मामले .इसके एक उपयुक्त डीलोकेटर, कंस्ट्रक्टर फेंकता है अगर संकलक तारों के लिए जिम्मेदार है।

ध्यान दें कि कन्स्ट्रक्टर में अधिग्रहित संसाधनों के साथ यह कम या ज्यादा असंबद्ध है, जो कि मेरे उत्तर के पहले प्रयास पर चर्चा की गई है - और यह एक प्रश्न है जिसमें कई अक्सर पूछे जाने वाले प्रश्न, लेख और पोस्टिंग में चर्चा की गई है।

+0

यह वास्तव में यहां (डुप्लिकेट?) प्रश्न का उत्तर देने का इरादा था: http://stackoverflow.com/questions/1674980/who-deletes-the-memory-allocated-during-a- new-operation-hhich-has-exception -इन –

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