c++ - स्टैक अवांछित क्या है?




stack (8)

स्टैक अवांछित क्या है? के माध्यम से खोजा लेकिन प्रबुद्ध जवाब नहीं मिल सका!


अनचाहे ढेर आमतौर पर अपवाद हैंडलिंग के संबंध में बात की जाती है। यहां एक उदाहरण दिया गया है:

void func( int x )
{
    char* pleak = new char[1024]; // might be lost => memory leak
    std::string s( "hello world" ); // will be properly destructed

    if ( x ) throw std::runtime_error( "boom" );

    delete [] pleak; // will only get here if x == 0. if x!=0, throw exception
}

int main()
{
    try
    {
        func( 10 );
    }
    catch ( const std::exception& e )
    {
        return 1;
    }

    return 0;
}

अगर अपवाद फेंक दिया जाता है तो pleak लिए आवंटित स्मृति खो जाएगी, जबकि s को आवंटित स्मृति किसी भी मामले में std::string destructor द्वारा ठीक से जारी की जाएगी। ढेर पर आवंटित ऑब्जेक्ट्स "अवांछित" होते हैं जब दायरा निकलता है (यहां स्कोप फ़ंक्शन func ।) यह स्वचालित (स्टैक) चर के विनाशकों को कॉल करने वाले कंपाइलर द्वारा किया जाता है।

अब यह एक बहुत ही शक्तिशाली अवधारणा है जिसे RAII कहा जाता है, जो संसाधन अधिग्रहण प्रारंभ है , जो हमें सी ++ में मेमोरी, डेटाबेस कनेक्शन, ओपन फाइल डिस्क्रिप्टर इत्यादि जैसे संसाधनों को प्रबंधित करने में मदद करता है।

अब यह हमें अपवाद सुरक्षा गारंटी प्रदान करता है


अवांछित ढेर ज्यादातर सी ++ अवधारणा है, इस बात से निपटने के साथ कि जब इसका दायरा निकलता है (या तो सामान्य रूप से, या अपवाद के माध्यम से) कैसे स्टैक-आवंटित वस्तुओं को नष्ट कर दिया जाता है।

मान लें कि आपके पास कोड का यह टुकड़ा है:

void hw() {
    string hello("Hello, ");
    string world("world!\n");
    cout << hello << world;
} // at this point, "world" is destroyed, followed by "hello"

एक सामान्य अर्थ में, एक स्टैक "unwind" एक फ़ंक्शन कॉल के अंत और स्टैक के बाद के पॉपिंग के अंत में काफी समानार्थी है।

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


जब एक अपवाद फेंक दिया जाता है और नियंत्रण को एक हैंडलर से ब्लॉक करने का प्रयास करता है, तो C ++ रन टाइम प्रयास ब्लॉक की शुरुआत के बाद से निर्मित सभी स्वचालित ऑब्जेक्ट्स के लिए विनाशकों को कॉल करता है। इस प्रक्रिया को ढेर अवांछित कहा जाता है। स्वचालित वस्तुओं को उनके निर्माण के विपरीत क्रम में नष्ट कर दिया जाता है। (स्वचालित ऑब्जेक्ट्स स्थानीय ऑब्जेक्ट्स हैं जिन्हें ऑटो या रजिस्टर घोषित किया गया है, या स्थैतिक या बाहरी घोषित नहीं किया गया है। जब भी प्रोग्राम ब्लॉक से बाहर निकलता है तो स्वचालित ऑब्जेक्ट x हटा दिया जाता है जिसमें x घोषित किया जाता है।)

यदि उपरोक्त या सरणी तत्वों वाले किसी ऑब्जेक्ट के निर्माण के दौरान अपवाद फेंक दिया जाता है, तो विनाशकों को केवल उन सबोबजेक्ट्स या सरणी तत्वों के लिए बुलाया जाता है जो अपवाद को फेंकने से पहले सफलतापूर्वक निर्मित किए जाते हैं। एक स्थानीय स्थैतिक वस्तु के लिए एक विनाशक केवल तभी बुलाया जाएगा जब ऑब्जेक्ट सफलतापूर्वक बनाया गया हो।


मुझे नहीं पता कि क्या आपने इसे अभी तक पढ़ा है, लेकिन कॉल स्टैक पर विकिपीडिया के लेख में एक सभ्य स्पष्टीकरण है।

unwinding:

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

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

निरंतरता लागू करते समय, ढेर (तार्किक रूप से) अवांछित होता है और फिर निरंतरता के ढेर के साथ फिर से चला जाता है। निरंतरता को लागू करने का यह एकमात्र तरीका नहीं है; उदाहरण के लिए, एकाधिक, स्पष्ट ढेर का उपयोग करके, निरंतरता का उपयोग केवल अपने ढेर को सक्रिय कर सकता है और एक मूल्य को पारित करने के लिए हवा को नियंत्रित कर सकता है। स्कीम प्रोग्रामिंग भाषा एक निरंतरता लागू होने पर नियंत्रण स्टैक के "अनचाहे" या "रिवाइंडिंग" पर निर्दिष्ट बिंदुओं में मनमाने ढंग से थंक्स को निष्पादित करने की अनुमति देती है।

निरीक्षण [संपादित करें]


मैंने एक ब्लॉग पोस्ट पढ़ा जिसने मुझे समझने में मदद की।

स्टैक अवांछित क्या है?

किसी भी भाषा में जो रिकर्सिव फ़ंक्शंस का समर्थन करता है (यानी फोरट्रान 77 और ब्रेनफ * सीके को छोड़कर बहुत कुछ सब कुछ) भाषा रनटाइम वर्तमान में निष्पादित करने वाले कार्यों का ढेर रखता है। अवांछित ढेर निरीक्षण का एक तरीका है, और संभावित रूप से संशोधित, उस ढेर।

आप ऐसा क्यों करना चाहते हो?

उत्तर स्पष्ट प्रतीत हो सकता है, लेकिन कई संबंधित, अभी भी अलग-अलग हैं, ऐसी परिस्थितियां जहां अनचाहे उपयोगी या आवश्यक है:

  1. एक रनटाइम नियंत्रण-प्रवाह तंत्र (सी ++ अपवाद, सी longjmp (), आदि के रूप में)।
  2. एक डीबगर में, उपयोगकर्ता को ढेर दिखाने के लिए।
  3. एक प्रोफाइलर में, ढेर का नमूना लेने के लिए।
  4. कार्यक्रम से ही (ढेर हैंडलर से ढेर दिखाने के लिए)।

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

आप here पूर्ण पोस्ट पा सकते here


सी ++ रनटाइम फेंक और पकड़ के बीच बनाए गए सभी स्वचालित चर को नष्ट करता है। नीचे दिए गए इस सरल उदाहरण में f1 () फेंकता है और मुख्य () कैच करता है, प्रकार बी और ए की वस्तुओं के बीच उस क्रम में ढेर पर बनाए जाते हैं। जब एफ 1 () फेंकता है, बी और ए के विनाशकों को बुलाया जाता है।

#include <iostream>
using namespace std;

class A
{
    public:
       ~A() { cout << "A's dtor" << endl; }
};

class B
{
    public:
       ~B() { cout << "B's dtor" << endl; }
};

void f1()
{
    B b;
    throw (100);
}

void f()
{
    A a;
    f1();
}

int main()
{
    try
    {
        f();
    }
    catch (int num)
    {
        cout << "Caught exception: " << num << endl;
    }

    return 0;
}

इस कार्यक्रम का उत्पादन होगा

B's dtor
A's dtor

ऐसा इसलिए है क्योंकि कार्यक्रम का कॉलस्टैक जब f1 () फेंकता दिखता है

f1()
f()
main()

इसलिए, जब f1 () पॉप हो जाता है, तो स्वचालित चर बी नष्ट हो जाता है, और फिर जब f () स्वचालित चर पॉप हो जाता है तो उसे नष्ट कर दिया जाता है।

उम्मीद है कि यह मदद करता है, कोडिंग खुश!


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





stack