स्टैक अनइंडिंग क्या है? के माध्यम से खोज की, लेकिन ज्ञानवर्धक उत्तर नहीं मिला!
स्टैक अनइंडिंग क्या है? के माध्यम से खोज की, लेकिन ज्ञानवर्धक उत्तर नहीं मिला!
जवाबों:
स्टैक अनइंडिंग आमतौर पर अपवाद से निपटने के संबंध में बात की जाती है। यहाँ एक उदाहरण है:
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 ++ में मेमोरी, डेटाबेस कनेक्शन, ओपन फाइल डिस्क्रिप्टर आदि जैसे संसाधनों को प्रबंधित करने में मदद करती है।
अब यह हमें अपवाद सुरक्षा गारंटी प्रदान करने की अनुमति देता है ।
delete [] pleak;
केवल तभी पहुंचता है यदि x == 0.
यह सब C ++ से संबंधित है:
परिभाषा : जैसा कि आप वस्तुओं को सांख्यिकीय रूप से बनाते हैं (ढेर मेमोरी में उन्हें आवंटित करने के विरोध में) और फ़ंक्शन कॉल करने के लिए, वे "स्टैक्ड अप" हैं।
जब एक गुंजाइश (कुछ भी द्वारा सीमांकित {
और }
) (का उपयोग करके बाहर निकल गया है return XXX;
सब कुछ है कि दायरे के भीतर नष्ट हो जाता है, गुंजाइश के अंत तक पहुँचने या एक अपवाद फेंक) (विनाशकर्ता सब कुछ के लिए कहा जाता है)। स्थानीय वस्तुओं को नष्ट करने और विनाशकर्ताओं को कॉल करने की इस प्रक्रिया को स्टैक अनइंडिंग कहा जाता है।
आपके पास स्टैक अनइंडिंग से संबंधित निम्नलिखित समस्याएं हैं:
मेमोरी लीक से बचना (ऐसी कोई चीज़ जो गतिशील रूप से आबंटित की गई हो, जिसे किसी स्थानीय ऑब्जेक्ट द्वारा प्रबंधित नहीं किया जाता है और विध्वंसक में साफ किया जाता है ) को लीक किया जाएगा - देखें कि RAII को निकोलाई द्वारा संदर्भित किया गया है, और बढ़ावा देने के लिए प्रलेखन :: scoped_ptr या बूस्ट का उपयोग करने का यह उदाहरण :: mutex :: scoped_lock ।
कार्यक्रम की संगति: C ++ विशिष्टताओं का वर्णन है कि किसी भी मौजूदा अपवाद को संभालने से पहले आपको कभी भी एक अपवाद नहीं फेंकना चाहिए। इसका मतलब यह है कि स्टैक अनइंडिंग प्रक्रिया को कभी भी अपवाद नहीं फेंकना चाहिए (या तो केवल कोड का उपयोग करें जो कि विध्वंसक में फेंकने के लिए गारंटी नहीं है, या विनाशकारी में सब कुछ घेरना चाहिए ) try {
और } catch(...) {}
।
यदि कोई विध्वंसक स्टैक अनइंडिंग के दौरान एक अपवाद फेंकता है तो आप अपरिभाषित व्यवहार की भूमि में समाप्त हो जाते हैं जो आपके कार्यक्रम को अनपेक्षित रूप से (सबसे सामान्य व्यवहार) या ब्रह्मांड को समाप्त करने का कारण बन सकता है (सैद्धांतिक रूप से संभव है लेकिन व्यवहार में अभी तक नहीं देखा गया है)।
एक सामान्य अर्थ में, एक फ़ंक्शन कॉल के अंत और स्टैक के बाद के पॉपिंग के साथ एक स्टैक "खोल" बहुत ज्यादा पर्याय है।
हालाँकि, विशेष रूप से C ++ के मामले में, स्टैक अनइंडिंग के साथ यह करना है कि किसी भी कोड ब्लॉक के शुरू होने के बाद से आवंटित वस्तुओं के लिए C ++ कैसे विध्वंसक कॉल करता है। ब्लॉक के भीतर बनाई गई वस्तुओं को उनके आवंटन के रिवर्स ऑर्डर में निपटाया जाता है।
try
ब्लॉक के बारे में कुछ खास नहीं है । किसी भी ब्लॉक में आवंटित स्टैक ऑब्जेक्ट (चाहे try
या नहीं) ब्लॉक के बाहर निकलने पर अनिच्छुक के अधीन हो।
स्टैक अनइंडिंग एक ज्यादातर C ++ कॉन्सेप्ट है, जिसके दायरे से बाहर निकलने पर स्टैक-आबंटित ऑब्जेक्ट्स को नष्ट कर दिया जाता है।
कहो कि आपके पास कोड का यह टुकड़ा है:
void hw() {
string hello("Hello, ");
string world("world!\n");
cout << hello << world;
} // at this point, "world" is destroyed, followed by "hello"
मुझे नहीं पता कि आप इसे अभी तक पढ़ते हैं, लेकिन कॉल स्टैक पर विकिपीडिया के लेख का एक अच्छा स्पष्टीकरण है।
तनाव मुक्त:
कहे गए फंक्शन से लौटने पर स्टैक के टॉप फ्रेम पॉप हो जाएंगे, शायद रिटर्न वैल्यू छोड़ देंगे। कार्यक्रम में कहीं और निष्पादन को फिर से शुरू करने के लिए स्टैक पर एक या एक से अधिक फ्रेम लगाने के सामान्य कार्य को स्टैक अनइंडिंग कहा जाता है और इसे तब निष्पादित किया जाना चाहिए जब गैर-स्थानीय नियंत्रण संरचनाओं का उपयोग किया जाता है, जैसे कि अपवाद हैंडलिंग के लिए उपयोग किया जाता है। इस स्थिति में, किसी फ़ंक्शन के स्टैक फ्रेम में अपवाद हैंडलर निर्दिष्ट करने वाली एक या अधिक प्रविष्टियाँ होती हैं। जब एक अपवाद को फेंक दिया जाता है, तो स्टैक अनचाहा होता है जब तक कि एक हैंडलर नहीं मिलता है जो फेंकने वाले अपवाद के प्रकार को संभालने (पकड़ने) के लिए तैयार किया जाता है।
कुछ भाषाओं में अन्य नियंत्रण संरचनाएं होती हैं जिनके लिए सामान्य अनइंडिंग की आवश्यकता होती है। पास्कल एक वैश्विक गोटो बयान को एक नेस्टेड फ़ंक्शन से नियंत्रण हटाने और पहले से लागू बाहरी फ़ंक्शन में स्थानांतरित करने की अनुमति देता है। इस ऑपरेशन के लिए स्टैक को अनचाहे रखने की आवश्यकता होती है, जिससे एन्कोडिंग बाहरी फ़ंक्शन के भीतर लक्ष्य स्टेटमेंट पर नियंत्रण स्थानांतरित करने के लिए उचित संदर्भ को पुनर्स्थापित करने के लिए आवश्यक के रूप में कई स्टैक फ़्रेमों को हटा दिया जाता है। इसी तरह, सी में सेटजम्प और लॉन्गजंप फ़ंक्शन हैं जो गैर-स्थानीय गोटो के रूप में कार्य करते हैं। आम लिस्प क्या नियंत्रण की अनुमति देता है जब स्टैक खोलना सुरक्षित-विशेष ऑपरेटर का उपयोग करके होता है।
एक निरंतरता को लागू करते समय, स्टैक (तार्किक रूप से) निराधार होता है और फिर निरंतरता के ढेर के साथ फिर से जुड़ता है। यह निरंतरता को लागू करने का एकमात्र तरीका नहीं है; उदाहरण के लिए, एकाधिक, स्पष्ट ढेर का उपयोग करते हुए, एक निरंतरता का अनुप्रयोग बस इसके ढेर को सक्रिय कर सकता है और पारित होने के लिए एक मूल्य को हवा दे सकता है। योजना प्रोग्रामिंग भाषा अनियंत्रित थ्रो को निर्दिष्ट बिंदुओं पर "अनइंडिंग" या नियंत्रण स्टैक के "रीवाइंडिंग" पर निष्पादित करने की अनुमति देती है जब एक निरंतरता को लागू किया जाता है।
निरीक्षण [संपादित करें]
मैंने एक ब्लॉग पोस्ट पढ़ी जिससे मुझे समझने में मदद मिली।
स्टैक अनइंडिंग क्या है?
किसी भी भाषा में जो पुनरावर्ती कार्यों का समर्थन करता है (यानी। फोरट्रान 77 और ब्रेनफ * सीके को छोड़कर सब कुछ) भाषा रनटाइम वर्तमान में निष्पादित होने वाले कार्यों का ढेर रखता है। स्टैक अनइंडिंग निरीक्षण का एक तरीका है, और संभवतः संशोधित करना, वह स्टैक।
आप ऐसा क्यों करना चाहते हो?
उत्तर स्पष्ट लग सकता है, लेकिन कई संबंधित हैं, फिर भी सूक्ष्म रूप से भिन्न हैं, ऐसी परिस्थितियां जहां अनइंडिंग उपयोगी या आवश्यक है:
- एक रनटाइम कंट्रोल-फ्लो मैकेनिज्म (C ++ अपवाद, C longjmp (), आदि) के रूप में।
- डिबगर में, उपयोगकर्ता को स्टैक दिखाने के लिए।
- एक प्रोफाइलर में, स्टैक का एक नमूना लेने के लिए।
- कार्यक्रम से ही (जैसे कि स्टैक दिखाने के लिए क्रैश हैंडलर से)।
इनकी अलग-अलग आवश्यकताएं हैं। इनमें से कुछ प्रदर्शन-महत्वपूर्ण हैं, कुछ नहीं हैं। कुछ को बाहरी फ्रेम से रजिस्टरों के पुनर्निर्माण की क्षमता की आवश्यकता होती है, कुछ को नहीं। लेकिन हम एक सेकंड में वह सब कर लेंगे।
सभी ने C ++ में अपवाद हैंडलिंग के बारे में बात की है। लेकिन, मुझे लगता है कि स्टैक अनइंडिंग के लिए एक और अर्थ है और यह डीबगिंग से संबंधित है। डिबगर को स्टैक अनइंडिंग करना होता है जब भी वर्तमान फ्रेम के पिछले फ्रेम में जाना होता है। हालाँकि, यह वर्चुअल अनडिंडिंग की तरह है क्योंकि इसे वर्तमान फ्रेम में वापस आने पर वापस करने की आवश्यकता होती है। इसके लिए उदाहरण gdb में ऊपर / नीचे / bt कमांड हो सकता है।
IMO, इस लेख में आरेख के नीचे दिए गए सुंदर तरीके से अगले निर्देश के मार्ग पर स्टैक अनइंडिंग के प्रभाव को स्पष्ट करता है (एक अपवाद को फेंक दिए जाने के बाद निष्पादित किया जाता है जो कि जारी नहीं किया गया है):
तस्वीर में:
दूसरे मामले में, जब अपवाद होता है, तो फ़ंक्शन कॉल स्टैक को रेखीय रूप से अपवाद हैंडलर के लिए खोजा जाता है। खोज अपवाद हैंडलर के साथ फ़ंक्शन पर समाप्त होती है अर्थात main()
एन्क्लोज़िंग try-catch
ब्लॉक के साथ , लेकिन फ़ंक्शन कॉल स्टैक से पहले सभी प्रविष्टियों को हटाने से पहले नहीं ।
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 () पॉपअप होता है तो स्वचालित चर नष्ट हो जाता है।
आशा है कि यह मदद करता है, खुश कोडिंग!
जब एक अपवाद को फेंक दिया जाता है और नियंत्रण एक कोशिश ब्लॉक से एक हैंडलर में गुजरता है, तो C ++ रन टाइम कोशिश ब्लॉक की शुरुआत के बाद से निर्मित सभी स्वचालित वस्तुओं के लिए विध्वंसक कहता है। इस प्रक्रिया को स्टैक अनइंडिंग कहा जाता है। स्वचालित वस्तुएं उनके निर्माण के रिवर्स ऑर्डर में नष्ट हो जाती हैं। (स्वचालित ऑब्जेक्ट स्थानीय ऑब्जेक्ट हैं जिन्हें ऑटो या रजिस्टर घोषित किया गया है, या स्थिर या बाहरी घोषित नहीं किया गया है। जब भी प्रोग्राम उस ब्लॉक से बाहर निकलता है जिसमें एक्स घोषित होता है, तो एक स्वचालित ऑब्जेक्ट एक्स हटा दिया जाता है।)
यदि किसी ऑब्जेक्ट के निर्माण के दौरान सब -जेक्ट्स या एरे तत्वों से युक्त एक अपवाद को फेंक दिया जाता है, तो डिस्ट्रक्टर्स को केवल उन सबोबजेक्ट्स या सरणी तत्वों के लिए बुलाया जाता है, जो अपवाद फेंके जाने से पहले सफलतापूर्वक बनाए गए थे। स्थानीय स्थैतिक वस्तु के लिए एक विध्वंसक केवल तभी कहा जाएगा जब वस्तु का सफलतापूर्वक निर्माण किया गया था।
जावा स्टैक में अनजाइडिंग या अनबाउंडिंग बहुत महत्वपूर्ण नहीं है (कचरा कलेक्टर के साथ)। कई अपवाद हैंडलिंग कागजात में मैंने इस अवधारणा (स्टैक अनइंडिंग) को देखा, विशेष रूप से उन लेखकों में सी या सी ++ में अपवाद हैंडलिंग से संबंधित है। try catch
ब्लॉक के साथ हम भूल जाते हैं: स्थानीय ब्लॉक के बाद सभी वस्तुओं से मुक्त स्टैक ।