स्टैक अनइंडिंग क्या है?


193

स्टैक अनइंडिंग क्या है? के माध्यम से खोज की, लेकिन ज्ञानवर्धक उत्तर नहीं मिला!


76
यदि वह नहीं जानता है कि यह क्या है, तो आप कैसे उससे यह जानने की उम्मीद कर सकते हैं कि वे C और C ++ के लिए समान नहीं हैं?
ड्रीमलैक्स

@dreamlax: तो, C & C ++ में "स्टैक अनइंडिंग" की अवधारणा अलग कैसे है?
नाशक

2
@PravasiMeet: C में कोई अपवाद हैंडलिंग नहीं है, इसलिए स्टैक अनइंडिंग बहुत सीधा है, हालाँकि, C ++ में, यदि कोई अपवाद फेंका जाता है या कोई फ़ंक्शन बाहर निकलता है, तो स्टैक अनइंडिंग में स्वत: पूर्ण अवधि के साथ किसी भी C ++ ऑब्जेक्ट को नष्ट करना शामिल होता है।
ड्रीमलैक्स

जवाबों:


150

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

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। स्टैक पर आबंटित वस्तुओं को "बाहर आना" होता है, जब गुंजाइश बाहर निकल जाती है (यहाँ गुंजाइश फ़ंक्शन की है func।) यह कंपाइलर द्वारा स्वचालित (स्टैक) चर के डिस्ट्रक्टर्स को कॉल सम्मिलित करके किया जाता है।

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

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


यह वास्तव में ज्ञानवर्धक था! इसलिए मुझे यह मिलता है: अगर मेरी प्रक्रिया किसी भी ब्लॉक को छोड़ने के दौरान अप्रत्याशित रूप से दुर्घटनाग्रस्त हो जाती है, जिस समय स्टैक पॉपप किया जा रहा था, तो ऐसा हो सकता है कि अपवाद हैंडलर कोड के बाद कोड बिल्कुल भी निष्पादित नहीं होने वाला है, और इससे मेमोरी लीक हो सकती है, आदि। ढेर भ्रष्टाचार आदि
राजेंद्र उप्पल

15
यदि प्रोग्राम "क्रैश" (यानी एक त्रुटि के कारण समाप्त हो जाता है), तो स्मृति समाप्त होने पर कोई भी मेमोरी लीकेज या ढेर भ्रष्टाचार अप्रासंगिक है।
टायलर मैकहेनरी

1
बिल्कुल सही। धन्यवाद। मैं आज थोड़ा डिस्लेक्सिक हो रहा हूं।
निकोलाई फेटिसोव

11
@TylerMcHenry: मानक यह गारंटी नहीं देता है कि संसाधन या स्मृति समाप्ति पर जारी किए गए हैं। हालांकि ऐसा करने के लिए ज्यादातर OS का होता है।
मूविंग डक

3
delete [] pleak;केवल तभी पहुंचता है यदि x == 0.
Jib

71

यह सब C ++ से संबंधित है:

परिभाषा : जैसा कि आप वस्तुओं को सांख्यिकीय रूप से बनाते हैं (ढेर मेमोरी में उन्हें आवंटित करने के विरोध में) और फ़ंक्शन कॉल करने के लिए, वे "स्टैक्ड अप" हैं।

जब एक गुंजाइश (कुछ भी द्वारा सीमांकित {और }) (का उपयोग करके बाहर निकल गया है return XXX;सब कुछ है कि दायरे के भीतर नष्ट हो जाता है, गुंजाइश के अंत तक पहुँचने या एक अपवाद फेंक) (विनाशकर्ता सब कुछ के लिए कहा जाता है)। स्थानीय वस्तुओं को नष्ट करने और विनाशकर्ताओं को कॉल करने की इस प्रक्रिया को स्टैक अनइंडिंग कहा जाता है।

आपके पास स्टैक अनइंडिंग से संबंधित निम्नलिखित समस्याएं हैं:

  1. मेमोरी लीक से बचना (ऐसी कोई चीज़ जो गतिशील रूप से आबंटित की गई हो, जिसे किसी स्थानीय ऑब्जेक्ट द्वारा प्रबंधित नहीं किया जाता है और विध्वंसक में साफ किया जाता है ) को लीक किया जाएगा - देखें कि RAII को निकोलाई द्वारा संदर्भित किया गया है, और बढ़ावा देने के लिए प्रलेखन :: scoped_ptr या बूस्ट का उपयोग करने का यह उदाहरण :: mutex :: scoped_lock

  2. कार्यक्रम की संगति: C ++ विशिष्टताओं का वर्णन है कि किसी भी मौजूदा अपवाद को संभालने से पहले आपको कभी भी एक अपवाद नहीं फेंकना चाहिए। इसका मतलब यह है कि स्टैक अनइंडिंग प्रक्रिया को कभी भी अपवाद नहीं फेंकना चाहिए (या तो केवल कोड का उपयोग करें जो कि विध्वंसक में फेंकने के लिए गारंटी नहीं है, या विनाशकारी में सब कुछ घेरना चाहिए ) try {और } catch(...) {}

यदि कोई विध्वंसक स्टैक अनइंडिंग के दौरान एक अपवाद फेंकता है तो आप अपरिभाषित व्यवहार की भूमि में समाप्त हो जाते हैं जो आपके कार्यक्रम को अनपेक्षित रूप से (सबसे सामान्य व्यवहार) या ब्रह्मांड को समाप्त करने का कारण बन सकता है (सैद्धांतिक रूप से संभव है लेकिन व्यवहार में अभी तक नहीं देखा गया है)।


2
इसके विपरीत। जबकि गोटो का दुरुपयोग नहीं किया जाना चाहिए, वे MSVC में स्टैक अनइंडिंग का कारण बनते हैं (जीसीसी में नहीं, इसलिए यह संभवतः एक विस्तार है)। setjmp और longjmp इसे कुछ कम लचीलेपन के साथ एक क्रॉस प्लेटफॉर्म तरीके से करते हैं।
पैट्रिक Niedzielski

10
मैंने अभी इसे जीसीसी के साथ परीक्षण किया है और यह सही ढंग से विध्वंसक कॉल करता है जब आप एक कोड ब्लॉक से बाहर निकलते हैं। इस लिंक में बताए अनुसार stackoverflow.com/questions/334780/… - देखें , यह मानक का हिस्सा है।
दमन

1
इस क्रम में निकोलाई, जिरस्टा और आपका जवाब पढ़ना अब समझ में आता है!
n611x007

@sashoalm क्या आपको लगता है कि सात साल बाद किसी पोस्ट को संपादित करना जरूरी है?
डेविड होल्ज़र

41

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

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


4
tryब्लॉक के बारे में कुछ खास नहीं है । किसी भी ब्लॉक में आवंटित स्टैक ऑब्जेक्ट (चाहे tryया नहीं) ब्लॉक के बाहर निकलने पर अनिच्छुक के अधीन हो।
क्रिस जस्टर-यंग

जब से मैंने बहुत सी ++ कोडिंग की है, तब से यह एक समय है। मुझे उस उत्तर को गहराई से खोदना था। ; पी
जिस्टा

चिंता मत करो। हर किसी के पास कभी-कभी "अपना बुरा" होता है।
बिटकॉइन

13

स्टैक अनइंडिंग एक ज्यादातर C ++ कॉन्सेप्ट है, जिसके दायरे से बाहर निकलने पर स्टैक-आबंटित ऑब्जेक्ट्स को नष्ट कर दिया जाता है।

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

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

क्या यह किसी ब्लॉक पर लागू होता है? मेरा मतलब है कि अगर केवल {// कुछ स्थानीय वस्तुएं हैं}
राजेंद्र उप्पल

@ राजेंद्र: हां, एक अनाम ब्लॉक स्कोप के क्षेत्र को परिभाषित करता है, इसलिए यह भी मायने रखता है।
माइकल मायर्स

12

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

तनाव मुक्त:

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

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

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

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


9

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

स्टैक अनइंडिंग क्या है?

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

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

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

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

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

आप पूरी पोस्ट यहाँ पा सकते हैं


7

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


5
डिबगर एक्शन को आम तौर पर "स्टैक वॉकिंग" कहा जाता है जो बस स्टैक को पार्स कर रहा है। "स्टैक अनवाइंडिंग" का अर्थ न केवल "स्टैक वॉकिंग" है, बल्कि स्टैक पर मौजूद वस्तुओं के विनाशकों को भी बुलाता है।
अदिसक

@ Adisak मुझे नहीं पता था कि इसे "स्टैक वाकिंग" भी कहा जाता है। मैं हमेशा सभी डिबगर लेखों के संदर्भ में "स्टैक अनइंडिंग" देख रहा हूं और जीडीबी कोड के अंदर भी। मुझे लगा कि "स्टैक अनइंडिंग" अधिक उपयुक्त है क्योंकि यह हर फ़ंक्शन के लिए स्टैक जानकारी में झांकने के बारे में नहीं है, लेकिन फ्रेम जानकारी (सीएफएफआई को बौना) में शामिल करना शामिल है। यह एक के बाद एक फंक्शन इन-ऑर्डर है।
BBv

मुझे लगता है कि "स्टैक वॉकिंग" विंडोज द्वारा अधिक प्रसिद्ध बनाया गया है। इसके अलावा, मुझे एक उदाहरण कोड के रूप में मिला । dwarf मानक के डॉक्स के अलावा एक कोड । हालांकि सहमत हैं, यह वर्चुअल अनइंडिंग है। इसके अलावा, सवाल हर संभव अर्थ के लिए पूछ रहा प्रतीत होता है "स्टैक अनइंडिंग" सुझाव दे सकता है।
BBv

7

IMO, इस लेख में आरेख के नीचे दिए गए सुंदर तरीके से अगले निर्देश के मार्ग पर स्टैक अनइंडिंग के प्रभाव को स्पष्ट करता है (एक अपवाद को फेंक दिए जाने के बाद निष्पादित किया जाता है जो कि जारी नहीं किया गया है):

यहां छवि विवरण दर्ज करें

तस्वीर में:

  • शीर्ष एक सामान्य कॉल निष्पादन है (बिना किसी अपवाद के)।
  • नीचे एक जब एक अपवाद फेंक दिया जाता है।

दूसरे मामले में, जब अपवाद होता है, तो फ़ंक्शन कॉल स्टैक को रेखीय रूप से अपवाद हैंडलर के लिए खोजा जाता है। खोज अपवाद हैंडलर के साथ फ़ंक्शन पर समाप्त होती है अर्थात main()एन्क्लोज़िंग try-catchब्लॉक के साथ , लेकिन फ़ंक्शन कॉल स्टैक से पहले सभी प्रविष्टियों को हटाने से पहले नहीं


आरेख अच्छे हैं लेकिन स्पष्टीकरण थोड़ा उलझा हुआ है। ... एन्क्लोज़िंग ट्राई-कैच ब्लॉक के साथ, लेकिन फ़ंक्शन कॉल स्टैक से पहले सभी प्रविष्टियों को हटाने से पहले नहीं ...
अतुल

3

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

#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 () पॉप होता है, तो स्वचालित चर b नष्ट हो जाता है, और फिर जब f () पॉपअप होता है तो स्वचालित चर नष्ट हो जाता है।

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


2

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

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


आपको उस मूल लेख का लिंक प्रदान करना चाहिए जहां से आपने इस उत्तर को कॉपी किया है: IBM नॉलेज बेस - स्टैक
अनवाइंडिंग

0

जावा स्टैक में अनजाइडिंग या अनबाउंडिंग बहुत महत्वपूर्ण नहीं है (कचरा कलेक्टर के साथ)। कई अपवाद हैंडलिंग कागजात में मैंने इस अवधारणा (स्टैक अनइंडिंग) को देखा, विशेष रूप से उन लेखकों में सी या सी ++ में अपवाद हैंडलिंग से संबंधित है। try catchब्लॉक के साथ हम भूल जाते हैं: स्थानीय ब्लॉक के बाद सभी वस्तुओं से मुक्त स्टैक

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.