जब मैं `थ्रो` कुछ करता हूँ, तो इसे मेमोरी में कहाँ स्टोर किया जाता है


82

मैं समझता हूं कि जब कुछ thrown होता है, तो स्टैक उस बिंदु पर 'अनजाउंड' होता है, जहां वह पकड़ा जाता है, और प्रत्येक फ़ंक्शन संदर्भ में स्टैक पर क्लास इंस्टेंस के विध्वंसक चलाए जाते हैं (यही वजह है कि आपको एक डिस्ट्रक्टर से अपवाद नहीं फेंकना चाहिए - आप एक दूसरे को फेंकने का अंत कर सकते हैं) ... लेकिन मुझे आश्चर्य है कि स्मृति में जहां मैंने फेंकी गई वस्तु को संग्रहीत किया है, जबकि ऐसा होता है?

क्या यह कार्यान्वयन पर निर्भर है? यदि हां, तो क्या कोई विशेष विधि सबसे लोकप्रिय संकलक द्वारा उपयोग की जाती है?


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

@ केरैक: मुझे लगता है कि अधिक संभावना है, ऑब्जेक्ट को "नीचे" पर स्टैक तरीके से रखा गया है। उसके बाद ऊपर की ओर याद करते हुए, यह याद रखें कि यह कहाँ था, और एक बार जब आप समाप्त कर लेते हैं (किसी भी पकड़ को शामिल करते हुए संदर्भ द्वारा अपवाद को संबोधित करने का अवसर देता है, और raiseइसे फिर से ), इसे नष्ट कर दें। ढेर आवंटन के साथ मुद्दा यह है कि, यदि आप अपवाद को आवंटित करने का आपका प्रयास विफल हो जाता है तो आप क्या करते हैं? आपको गर्भपात करना होगा (जैसे आप स्टैक ओवरफ्लो के लिए होंगे यदि इसे स्टैक पर रखा जाए तो जगह की कमी के कारण "विफल हो जाता है")। जावा के विपरीत कार्यान्वयन को इसके बजाय एक अलग अपवाद को फेंकने की अनुमति नहीं है।
स्टीव जेसप जूल

@Steve: यह भी संभव है - किरिल के लेख में कहा गया है कि अपवाद को स्टैक पर आवंटित किया गया है, और एक सहायक जानकारी संरचना इसके पते और डेलेटर आदि को रिकॉर्ड करती है, लेकिन मुझे लगता है कि कार्यान्वयन किसी भी तरह से ऐसा करने के लिए स्वतंत्र हैं?
केरेक एस.बी. जूल

@ केरैक: हाँ, बाधा के अधीन है कि इसे वास्तव में अपवाद फेंकना है, और सामान्य मुद्दा जो स्टैक से बाहर निकलता है, इस तरह की जिम्मेदारियों से बचने के लिए कार्यान्वयन की अनुमति देता है :-) यदि आप इसे स्टैक पर रखते हैं, तो क्योंकि अपवाद फेंक दिए गए हैं थ्रो एक्सप्रेशन के स्थिर प्रकार से, पूरे फंक्शन के लिए आपके स्टैक फ्रेम में उस प्रकार को फेंकने के लिए जो भी जगह की आवश्यकता होती है, शामिल हो सकता है, हालांकि मुझे नहीं पता कि MSVC ऐसा करता है या नहीं।
स्टीव जेसप जूल

जवाबों:


51

हां, उत्तर संकलक-निर्भर है।

मेरे संकलक ( g++ 4.4.3) के साथ एक त्वरित प्रयोग से पता चलता है कि इसकी रनटाइम लाइब्रेरी पहले mallocअपवाद के लिए मेमोरी की कोशिश करती है और, असफल होने पर, डेटा सेगमेंट पर रहने वाले प्रोसेस-वाइड "आपातकालीन बफर" के भीतर स्थान आवंटित करने का प्रयास करती है। अगर वह काम नहीं करता है, तो यह कॉल करता है std::terminate()

ऐसा प्रतीत होता है कि आपातकालीन बफर का मुख्य उद्देश्य std::bad_allocप्रक्रिया को हटाने के बाद फेंकने में सक्षम होना है (जिस स्थिति में mallocकॉल विफल हो जाएगा)।

प्रासंगिक कार्य है __cxa_allocate_exception:

extern "C" void *
__cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw()
{
  void *ret;

  thrown_size += sizeof (__cxa_refcounted_exception);
  ret = malloc (thrown_size);

  if (! ret)
    {
      __gnu_cxx::__scoped_lock sentry(emergency_mutex);

      bitmask_type used = emergency_used;
      unsigned int which = 0;

      if (thrown_size > EMERGENCY_OBJ_SIZE)
        goto failed;
      while (used & 1)
        {
          used >>= 1;
          if (++which >= EMERGENCY_OBJ_COUNT)
            goto failed;
        }

      emergency_used |= (bitmask_type)1 << which;
      ret = &emergency_buffer[which][0];

    failed:;

      if (!ret)
        std::terminate ();
    }

  // We have an uncaught exception as soon as we allocate memory.  This
  // yields uncaught_exception() true during the copy-constructor that
  // initializes the exception object.  See Issue 475.
  __cxa_eh_globals *globals = __cxa_get_globals ();
  globals->uncaughtExceptions += 1;

  memset (ret, 0, sizeof (__cxa_refcounted_exception));

  return (void *)((char *)ret + sizeof (__cxa_refcounted_exception));
}

मुझे नहीं पता कि यह योजना कितनी विशिष्ट है।


"जिस स्थिति में mallocकॉल विफल होता है" अच्छी तरह से, आमतौर पर, लेकिन जरूरी नहीं।
अयक्सन हक्वेर्डिली

20

से यह पेज :

अपवादों को फेंके जाने के लिए भंडारण की आवश्यकता होती है। जब तक यह हैंडलर द्वारा उपयोग किया जाएगा, और थ्रेड-सुरक्षित होना चाहिए, तब तक यह संग्रहण स्थिर रहना चाहिए। इसलिए अपवाद ऑब्जेक्ट स्टोरेज को आम तौर पर हीप में आवंटित किया जाएगा , हालांकि कार्यान्वयन कम आपातकालीन स्थिति के तहत खराब_लोक अपवादों का समर्थन करने के लिए एक आपातकालीन बफर प्रदान कर सकता है

अब, यह केवल इटेनियम एबीआई है और मैं जीसीसी, क्लैंग और एमएसवीसी के विवरणों की तलाश कर रहा हूं। हालांकि, मानक कुछ भी निर्दिष्ट नहीं करता है और यह अपवाद भंडारण को लागू करने का स्पष्ट तरीका प्रतीत होता है, इसलिए ...


1
अभी भी विवरण की तलाश है? कभी-कभी एक से अधिक जवाब स्वीकार करने में सक्षम होना अच्छा होगा :)
sje397

4

मुझे नहीं पता कि यह आपके प्रश्न का उत्तर देगा, लेकिन यह (कैसे एक सी ++ संकलक अपवाद अपवाद को हैंडल करता है) बिल्कुल अपवाद हैंडलिंग के बारे में उत्कृष्ट लेख है:। मैं इसकी पुरजोर सलाह देता हूँ (:

संक्षिप्त उत्तर के लिए क्षमा करें, लेकिन लेख में पूरी जानकारी महान है, मैं यहां कुछ जानकारी नहीं चुन सकता हूं और न ही पोस्ट कर सकता हूं।


excpt_infoउस पृष्ठ में खोजें , यह कुछ जानकारी देता है कि MSVC यह कैसे करता है।
स्टीव जेसोप

1
यह लिंक वास्तव में वर्णन करता है कि इसे एक अच्छे कार्यान्वयन में कैसे नहीं किया जाता है। मुझे पता है कि कुछ पुराने वीसी ++ ने कुछ इस तरह का इस्तेमाल किया, लेकिन मुझे संदेह है कि आप इसे किसी भी आधुनिक संकलक में पाएंगे।
जेम्स कांजे

0

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


-2

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


3
आपका उत्तर स्वयं विरोधाभासी है।
ऑर्बिट

कैसे? यह एक कार्यान्वयन पर बाधाओं को प्रस्तुत करता है, जो मानक में निहित हैं।
बजे जेम्स कांजे जूल

एक उदाहरण: "यह ढेर पर नहीं हो सकता है" ... "एक कार्यान्वयन ढेर का सबसे अधिक उपयोग कर सकता है"। इसके अलावा, उत्तर का पूरा पहला भाग गलत है, जैसा कि अन्य उत्तरों में समझाया गया है (और, वास्तव में, आंशिक रूप से आपके दूसरे भाग में!)।
ऑर्बिट

मानक को std::bad_allocकाम करने की आवश्यकता है। इसका मतलब यह है कि एक कार्यान्वयन व्यवस्थित रूप से ढेर का उपयोग नहीं कर सकता है। मानक इसकी अनुमति नहीं देता है। मैं अपने दावों को मानक पर आधारित कर रहा हूं।
जेम्स कांजे

"व्यवस्थित रूप से" का FSVO, यह सही है। हालांकि, जैसा कि आप अपने उत्तर के दूसरे भाग में बताते हैं, एक कार्यान्वयन वास्तव में ढेर ^ H ^ H ^ H ^ Hfreestore का उपयोग विकल्पों के साथ कर सकता है।
ऑर्बिट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.