C ++ फ़ंक्शन में एक स्थिर चर का जीवनकाल क्या है?


373

यदि एक चर को staticफ़ंक्शन के दायरे में घोषित किया जाता है , तो इसे केवल एक बार आरंभीकृत किया जाता है और फ़ंक्शन कॉल के बीच इसके मूल्य को बनाए रखता है। वास्तव में इसका जीवनकाल क्या है? इसके निर्माणकर्ता और विध्वंसक कब कहा जाता है?

void foo() 
{ 
    static string plonk = "When will I die?";
}

जवाबों:


257

फ़ंक्शन staticचर का जीवनकाल पहली बार शुरू होता है [0] कार्यक्रम प्रवाह घोषणा का सामना करता है और यह कार्यक्रम समाप्ति पर समाप्त होता है। इसका मतलब यह है कि रन-टाइम को किसी पुस्तक को नष्ट करने के लिए अवश्य करना चाहिए, यदि वह वास्तव में निर्मित है।

इसके अतिरिक्त, चूंकि मानक कहता है कि स्थैतिक वस्तुओं के विध्वंसक को उनके निर्माण के पूर्ण होने के विपरीत क्रम में चलना चाहिए [1] , और निर्माण का क्रम विशिष्ट कार्यक्रम चलाने पर निर्भर हो सकता है, निर्माण के क्रम को ध्यान में रखा जाना चाहिए। ।

उदाहरण

struct emitter {
    string str;
    emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
    ~emitter() { cout << "Destroyed " << str << endl; }
};

void foo(bool skip_first) 
{
    if (!skip_first)
        static emitter a("in if");
    static emitter b("in foo");
}

int main(int argc, char*[])
{
    foo(argc != 2);
    if (argc == 3)
        foo(false);
}

आउटपुट:

C:> sample.exe
foo में बनाया गया foo में
नष्ट

सी:> sample.exe 1
निर्मित में अगर
foo में बनाया गया
foo में नष्ट कर दिया
है, तो में नष्ट कर दिया

सी:> sample.exe 1 2
foo में बनाया गया
में बनाया गया है, तो
अगर में नष्ट कर दिया
foo में नष्ट कर दिया

[0]चूंकि C ++ 98 [2] में कई थ्रेड्स का कोई संदर्भ नहीं है कि यह बहु-थ्रेडेड वातावरण में कैसे व्यवहार किया जाएगा अनिर्दिष्ट, और रोडी उल्लेख के रूप में समस्याग्रस्त हो सकता है ।

[1] C ++ 98 सेक्शन 3.6.3.1 [basic.start.term]

[2]C ++ 11 स्टैटिक्स में एक थ्रेड सुरक्षित तरीके से इनिशियलाइज़ किया जाता है, इसे मैजिक स्टैटिक्स के रूप में भी जाना जाता है ।


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

1
यदि फ़ंक्शन को कई थ्रेड्स द्वारा बुलाया जा सकता है, तो इसका मतलब यह है कि आपको यह सुनिश्चित करने की आवश्यकता है कि स्थिर घोषणाओं को C ++ 98 में एक म्यूटेक्स द्वारा संरक्षित किया जाना चाहिए ??
एल्यूरोकोड

1
वैश्विक वस्तुओं के "विध्वंसक" को अपने निर्माण के पूरा होने के रिवर्स ऑर्डर में चलना चाहिए "यहां लागू नहीं होता है, क्योंकि ये ऑब्जेक्ट वैश्विक नहीं हैं। स्थैतिक या थ्रेड भंडारण अवधि के साथ स्थानीय लोगों का विनाश क्रम शुद्ध लिफो की तुलना में काफी अधिक जटिल है, खंड 3.6.3 देखें[basic.start.term]
बेन वायगट

2
वाक्यांश "प्रोग्राम समाप्ति पर" सख्ती से सही नहीं है। Windows dll में स्टैटिक्स के बारे में क्या है जो गतिशील रूप से लोड और अनलोड किए जाते हैं? जाहिर है सी ++ मानक असेंबली के साथ बिल्कुल भी व्यवहार नहीं करता है (यदि यह किया गया तो अच्छा होगा), लेकिन मानक क्या कहता है, इसके बारे में एक स्पष्टीकरण लगभग अच्छा होगा। यदि वाक्यांश "प्रोग्राम समाप्ति पर" शामिल किया गया था, तो यह तकनीकी रूप से सी + + के किसी भी कार्यान्वयन को गतिशील रूप से अनलोडेड असेंबली गैर-अनुरूपता के साथ करेगा।
रोजर सैंडर्स

2
@ मैं नहीं मानता कि मानक स्पष्ट रूप से गतिशील पुस्तकालयों की अनुमति देता है, लेकिन अब तक मैं यह भी नहीं मानता था कि मानक में ऐसा कुछ भी था जो इसके कार्यान्वयन के साथ बाधाओं पर था। बेशक, यहां कड़ाई से भाषा बोलना यह नहीं बताता है कि स्थैतिक वस्तुओं को अन्य साधनों के माध्यम से पहले नष्ट नहीं किया जा सकता है, बस उन्हें मुख्य या कॉलिंग एसटीडी से बाहर निकलने पर नष्ट कर दिया जाना चाहिए :: बाहर निकलें। एक बहुत अच्छी लाइन, हालांकि मुझे लगता है।
रोजर सैंडर्स

125

मोति आदेश के बारे में सही है, लेकिन विचार करने के लिए कुछ अन्य चीजें हैं:

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

यदि आपके पास ऊपर के रूप में एक स्थानीय स्थैतिक है, और fooकई थ्रेड्स से कॉल किया जाता है, तो आपके पास दौड़ की स्थिति हो सकती है जो plonkगलत तरीके से या कई बार आरंभीकृत होती है। इसके अलावा, इस मामले में plonkएक अलग धागे से विनाश हो सकता है जिसने इसे बनाया था।

मानक के अनुसार, मैं स्थानीय स्थैतिक विनाश के वास्तविक क्रम से बहुत सावधान रहूंगा, क्योंकि यह संभव है कि आप अनजाने में स्थैतिक होने के बाद भी वैध होने पर भरोसा कर सकते हैं, और इसे ट्रैक करना वास्तव में मुश्किल है।


68
C ++ 0x के लिए आवश्यक है कि स्थैतिक आरंभीकरण थ्रेड सुरक्षित हो। इसलिए सावधान रहें लेकिन चीजें केवल बेहतर होंगी।
deft_code

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

मैं एक नोबॉल का एक सा हूँ, लेकिन इस नीति को भाषा में लागू क्यों नहीं किया जा सकता है?
cjcurrie

9
C ++ 11 के बाद से, यह अब कोई समस्या नहीं है। उसी के अनुसार मोति का उत्तर अद्यतन है।
नीलांजन बसु

10

मौजूदा स्पष्टीकरण मानक से वास्तविक नियम के बिना वास्तव में पूर्ण नहीं हैं, 6.7 में पाया गया:

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


8

एफडब्ल्यूआईडब्ल्यू, कोडगियर सी ++ बिल्डर मानक के अनुसार अपेक्षित क्रम में विनाश नहीं करता है।

C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if

... जो विनाश के आदेश पर भरोसा नहीं करने का एक और कारण है!


57
अच्छा तर्क नहीं। मैं कहूंगा कि यह इस संकलक का उपयोग न करने के एक तर्क से अधिक है।
मार्टिन यॉर्क

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

17
मैं सहमत हूँ, सिवाय इसके कि मैं इसे वाक्यांश के रूप में "क्या संकलक समस्याओं का कारण बनता हूं, और भाषा के कौन से क्षेत्रों में वे इसे करते हैं:? -पी
स्टीव जेसप

0

स्थैतिक चर एक बार भूमिका निभाते हैं कर रहे हैं प्रोग्राम निष्पादन शुरू होता है और यह प्रोग्राम निष्पादन समाप्त हो जाती है जब तक उपलब्ध रहते हैं।

मेमोरी के डेटा सेगमेंट में स्टेटिक वैरिएबल बनाए जाते हैं ।


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