2010-06-23 9 views
14

सी पृष्ठभूमि से आ रहा है, मैंने हमेशा माना है कि पीओडी प्रकार (जैसे इंट्स) कभी भी स्वचालित रूप से शून्य-प्रारंभिक रूप से सी ++ में प्रारंभ नहीं हुए थे, लेकिन ऐसा लगता है कि यह सादा गलत था!सी ++ पीओडी प्रकार कब शून्य-प्रारंभिक होते हैं?

मेरी समझ यह है कि कोड स्निपेट में दिखाए गए अनुसार केवल 'नग्न' गैर स्थैतिक पीओडी मान शून्य-भरे नहीं होते हैं। क्या मुझे यह सही मिला है, और क्या कोई अन्य महत्वपूर्ण मामला है जिसे मैंने याद किया है?

static int a; 

struct Foo { int a;}; 

void test() 
{ 
    int b;  
    Foo f; 
    int *c = new(int); 
    std::vector<int> d(1); 

    // At this point... 
    // a is zero 
    // f.a is zero 
    // *c is zero 
    // d[0] is zero 
    // ... BUT ... b is undefined  
} 
+0

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

+0

यह ओएस के आवंटित होने पर स्मृति को शून्य से बाहर रखने के लिए अपमानजनक प्रतीत होता है। – Alan

+2

आप माइकल बुर द्वारा उत्कृष्ट, संबंधित पोस्ट को भी जवाब में पढ़ सकते हैं [टाइप नाम के बाद कोष्ठक नए के साथ अंतर बनाते हैं?] (Http://stackoverflow.com/questions/620137/do-the-parentheses- बाद में टाइप-नाम-मेक-ए-फर्क-इन-न्यू/620402 # 620402) –

उत्तर

16

मान लिया जाये कि आप a संशोधित नहीं किया है के लिए शुरू किया जाना चाहिए test() पर कॉल करने से पहले, a में शून्य का मान है, क्योंकि स्थिर संग्रहण अवधि वाले ऑब्जेक्ट शून्य-प्रारंभ होते हैं जब प्रोग्राम शुरू होता है।

d[0] शून्य का मान है, क्योंकि std::vector<int> d(1) द्वारा निर्मित कन्स्ट्रक्टर का दूसरा पैरामीटर है जो डिफ़ॉल्ट तर्क लेता है; उस दूसरे तर्क को सदिश के निर्माण के सभी तत्वों में कॉपी किया गया है। डिफ़ॉल्ट तर्क T() है, इसलिए अपने कोड के बराबर है:

std::vector<int> d(1, int()); 

आप सही b एक अनिश्चित मूल्य नहीं है कर रहे हैं।

f.a और *c दोनों के पास अनिश्चित मूल्य भी हैं। उन्हें प्रारंभ (जो पॉड प्रकार के लिए शून्य आरंभीकरण के समान है) मूल्य के लिए, आप उपयोग कर सकते हैं:

Foo f = Foo();  // You could also use Foo f((Foo())) 
int* c = new int(); // Note the parentheses 
+0

अधिकतर सहमत हुए; केवल मुझे यकीन नहीं है कि क्यों 'फू एफ' संश्लेषित कन्स्ट्रक्टर को कॉल नहीं करता है, और यदि ऐसा होता है, तो यह 'Foo f = Foo();' ... – xtofl

+0

से अलग क्यों होगा। और आपकी टिप्पणी में भयानक लिंक के लिए डबल धन्यवाद! – Roddy

+1

@xtofl: यदि कोई प्रारंभिककर्ता मौजूद नहीं है (जैसा कि पीओडी प्रकार ऑब्जेक्ट के लिए 'Foo f; ') के मामले में है, तो उस ऑब्जेक्ट को अनियंत्रित छोड़ दिया गया है। 'Foo f = Foo(); 'मान-प्रारंभिक' Foo' बनाता है (यही वह है जो 'Foo()' भाग करता है) और उसके बाद 'f' प्रारंभ करने के लिए इसका उपयोग करता है। –

1

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

अगर मैं गलत नहीं हूँ, अपने कोड में:

  • एक अप्रारंभीकृत होना चाहिए।
  • ग एक नया (अप्रारंभीकृत) पर ले जाना चाहिए अप्रारंभीकृत किया जाना चाहिए int
  • घ [0] (के रूप में आप सही ढंग से अनुमान लगाया)
+0

मुझे लगता है कि आज यूनिक्स जैसी ऑपरेटिंग सिस्टम में 'ए' को' 0' तक साफ़ कर दिया जाएगा। तकनीकी रूप से, 'ए' '.bs 'सेगमेंट में होगा, जो आमतौर पर' मुख्य() 'कॉल होने से पहले सभी 0 पर सेट हो जाता है। –

+0

हां, लेकिन मेरा मुद्दा यह था कि उसे उस पर भरोसा नहीं करना चाहिए भले ही मान कोड में शून्य के रूप में दिखाई देता है। स्पष्ट प्रारंभिक तरीका यहां जाने का तरीका है। – utnapistim

+1

'परीक्षण'() 'को कॉल करने से पहले 'ए' संशोधित नहीं किया गया है, तो इसका शून्य शून्य होगा। स्थिर स्टोरेज अवधि वाले ऑब्जेक्ट्स प्रोग्राम शुरू होने पर शून्य-प्रारंभिक होते हैं। –

0

मेरे लिए, पॉड प्रकार स्मृति वे रखा जाता है की ओर से निर्भर करता है प्रारंभ कर रहे हैं। आपके static int a को डेटा सेगमेंट पर आवंटित किया गया है, इसलिए स्टार्टअप पर इसका डिफ़ॉल्ट मान है। हालांकि, मुझे लगता है कि एफ आपके उदाहरण में inizialized नहीं है ...

0

वे नहीं करते हैं। डीबग बिट्स संस्करण ऐसा कर सकते हैं, लेकिन आम तौर पर इसे सिर्फ स्मृति में रखा जाता है, और स्मृति में मूल्य होने के लिए जो भी हुआ, उसे शुरू किया जाता है।

1

ध्यान दें कि सुरक्षा सुविधा के रूप में ओएस द्वारा किए गए शून्य-प्रारंभिकरण को आमतौर पर पहली बार स्मृति आवंटित किया जाता है। इसके द्वारा मेरा मतलब ढेर, ढेर और डेटा खंडों में कोई भी खंड है। ढेर और डेटा अनुभाग आमतौर पर निश्चित आकार के होते हैं, और जब एप्लिकेशन को स्मृति में लोड किया जाता है तब प्रारंभ किया जाता है।

डेटा सेगमेंट (स्थिर/वैश्विक डेटा और कोड युक्त) आमतौर पर "पुनः उपयोग नहीं किया जाता" है, हालांकि यदि आप गतिशील रूप से रनटाइम पर कोड लोड करते हैं तो यह मामला नहीं हो सकता है।

स्टैक सेगमेंट में स्मृति हर समय फिर से उपयोग की जाती है। स्थानीय चर, फ़ंक्शन स्टैक फ़्रेम इत्यादि .. सभी का लगातार उपयोग किया जाता है और फिर से उपयोग किया जाता है और हर बार प्रारंभ नहीं किया जाता है - बस जब एप्लिकेशन को पहले लोड किया जाता है।

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

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

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

कभी-कभी जब आप डीबग मोड में कोई एप्लिकेशन चलाते हैं, हालांकि, कुछ डीबग मोड रनटाइम प्रत्येक आवंटन पर स्टैक और ढेर डेटा प्रारंभ करते हैं (इसलिए आपका फू फ़ील्ड हमेशा प्रारंभ किया जाएगा)। हालांकि, विभिन्न डीबग रनटाइम डेटा को विभिन्न मानों में प्रारंभ करते हैं। कुछ शून्य प्रारंभ होते हैं, और कुछ "मार्कर" मान में प्रारंभ होते हैं।

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

+0

वहां * बिल्कुल * गारंटी है कि ओपी के उदाहरण में 'ए 'शून्य शुरू हो जाएगा। –

संबंधित मुद्दे