डिफ़ॉल्ट, मान और शून्य आरंभीकरण गड़बड़


88

मैं मूल्य और डिफ़ॉल्ट- और शून्य-आरंभीकरण के बारे में बहुत उलझन में हूं। और विशेषकर जब वे विभिन्न मानकों C ++ 03 और C ++ 11 (और C ++ 14 ) के लिए किक करते हैं ।

मैं उद्धृत कर रहा हूं और वास्तव में अच्छे उत्तर का विस्तार करने की कोशिश कर रहा हूं- / Default- / Zero- Init C ++ 98 और C ++ 03 यहां इसे और अधिक सामान्य बनाने के लिए क्योंकि यह बहुत सारे उपयोगकर्ताओं की मदद करेगा यदि कोई व्यक्ति इसे भरने में मदद कर सकता है। क्या होता है, इसके बारे में एक अच्छा अवलोकन करने के लिए अंतराल की आवश्यकता होती है

संक्षेप में उदाहरण द्वारा पूर्ण अंतर्दृष्टि:

कभी-कभी नए ऑपरेटर द्वारा दी गई मेमोरी को इनिशियलाइज़ किया जाएगा, और कभी-कभी यह इस बात पर निर्भर नहीं करेगा कि आप जिस प्रकार से नया कर रहे हैं वह एक POD (सादा पुराना डेटा) है , या यदि यह एक वर्ग है जिसमें POD सदस्य हैं और एक का उपयोग कर रहा है संकलक-जनित डिफ़ॉल्ट निर्माता।

  • में सी ++ 1998 : प्रारंभ के 2 प्रकार देखते हैं शून्य और डिफ़ॉल्ट-आरंभीकरण
  • में सी ++ 2003 प्रारंभ, के एक 3 प्रकार मूल्य-प्रारंभ जोड़ा गया है।
  • में सी ++ 2011 / सी ++ 2014 केवल सूची-प्रारंभ जोड़ा गया था और के लिए नियमों को value- / default- / शून्य प्रारंभ थोड़ा बदल दिया है।

मान लीजिये:

struct A { int m; };                     
struct B { ~B(); int m; };               
struct C { C() : m(){}; ~C(); int m; };  
struct D { D(){}; int m; };             
struct E { E() = default; int m;}; /** only possible in c++11/14 */  
struct F {F(); int m;};  F::F() = default; /** only possible in c++11/14 */

C ++ 98 संकलक में, निम्नलिखित होने चाहिए :

  • new A - अनिश्चित मान ( APOD है)
  • new A()- शून्य-इनिशियलाइज़
  • new B - डिफ़ॉल्ट निर्माण ( B::mअसिंचित है, Bगैर-पीओडी है)
  • new B()- डिफ़ॉल्ट निर्माण ( B::mअसिंचित है)
  • new C - डिफ़ॉल्ट निर्माण ( C::mशून्य-प्रारंभिक है, Cगैर-पीओडी है)
  • new C()- डिफ़ॉल्ट निर्माण ( C::mशून्य प्रारंभिक है)
  • new D - डिफ़ॉल्ट निर्माण ( D::mअसिंचित है, Dगैर-पीओडी है)
  • new D()- डिफ़ॉल्ट निर्माण? ( D::mअनधिकृत है)

C ++ 03 अनुरूप कंपाइलर में, चीजों को इस तरह काम करना चाहिए:

  • new A - अनिश्चित मान ( APOD है)
  • new A() - मूल्य-आरंभीकरण A, जो शून्य-आरंभीकरण है क्योंकि यह एक पीओडी है।
  • new B - डिफ़ॉल्ट-इनिशियलाइज़ (पत्तियां B::mअसिंचित है, Bगैर-पीओडी है)
  • new B() - वैल्यू-इनिशियलाइज़ेशन Bजो सभी फ़ील्ड्स को इनिशियलाइज़ करता है, क्योंकि उसका डिफॉल्ट ctor कंपाइलर है, जो यूज़र-डिफ़ाइंड के विपरीत है।
  • new C - डिफ़ॉल्ट-इनिशियलाइज़ करता है C, जो डिफ़ॉल्ट ctor को कॉल करता है। ( C::mशून्य-प्रारंभिक है, Cगैर-पीओडी है)
  • new C() - वैल्यू-इनिशियलाइज़ C, जो डिफॉल्ट ctor को कॉल करता है। ( C::mशून्य-आरंभिक है)
  • new D - डिफ़ॉल्ट निर्माण ( D::mअसिंचित है, Dगैर-पीओडी है)
  • new D() - D को इनिशियलाइज़ करता है? , जो डिफ़ॉल्ट ctor को कॉल करता है (असिंचित D::mहै)

इटैलिक मूल्य और मान? अनिश्चितताएं हैं, कृपया इसे ठीक करने में मदद करें :-)

C ++ 11 अनुरूप कंपाइलर में, चीजों को इस तरह से काम करना चाहिए:

??? (कृपया मदद करें अगर मैं यहाँ शुरू करूँ तो यह वैसे भी गलत हो जाएगा)

C ++ 14 अनुरूप कंपाइलर में, चीजों को इस तरह से काम करना चाहिए: ??? (कृपया मदद करें अगर मैं यहां से शुरू करूं तो यह गलत हो जाएगा) (उत्तर पर आधारित ड्राफ्ट)

  • new A - डिफ़ॉल्ट-इनिशियलाइज़ A, कंपाइलर जीन। ctor, (leavs A::muninitialized) ( APOD है)

  • new A() - मूल्य-इनिशियलाइज़ A, जो कि शून्य-आरंभीकरण है। 2. बिंदु [dcl.init] / 8 में

  • new B - डिफ़ॉल्ट-इनिशियलाइज़ B, कंपाइलर जीन। ctor, (leavs B::muninitialized) ( Bनॉन-पीओडी है)

  • new B() - वैल्यू-इनिशियलाइज़ेशन Bजो सभी फ़ील्ड्स को इनिशियलाइज़ करता है, क्योंकि उसका डिफॉल्ट ctor कंपाइलर है, जो यूज़र-डिफ़ाइंड के विपरीत है।

  • new C - डिफ़ॉल्ट-इनिशियलाइज़ करता है C, जो डिफ़ॉल्ट ctor को कॉल करता है। ( C::mशून्य-प्रारंभिक है, Cगैर-पीओडी है)

  • new C() - वैल्यू-इनिशियलाइज़ C, जो डिफॉल्ट ctor को कॉल करता है। ( C::mशून्य-आरंभिक है)

  • new D - डिफ़ॉल्ट-इनिशियलाइज़ D( गैर- D::mअधिकृत है, Dगैर-पीओडी है)

  • new D() - मूल्य-इनिशियलाइज़ D, जो डिफॉल्ट ctor को कॉल करता है (अनइंस्टॉलिज्ड D::mहै)

  • new E - डिफ़ॉल्ट-इनिशियलाइज़ E, जो COMP कहता है। जनरल। ctor। ( E::mगैर-सरकारी है, ई गैर-पीओडी है)

  • new E() - मूल्य आरंभ Eहै, जो शून्य आरंभ Eमें 2 बिंदु के बाद से [dcl.init] / 8 )

  • new F - डिफ़ॉल्ट-इनिशियलाइज़ F, जो COMP कहता है। जनरल। ctor। ( गैर- F::mअधिकृत है, Fगैर-पीओडी है)

  • new F() - मूल्य-initializes F, जो डिफ़ॉल्ट-आरंभ F के बाद से 1 में बिंदु [dcl.init] / 8 ( Fctor समारोह अगर यह उपयोगकर्ता के घोषित कर दिया और नहीं स्पष्ट रूप से चूक या अपनी पहली घोषणा पर नष्ट कर दिया है उपयोगकर्ता द्वारा प्रदान की है। लिंक )


यहाँ इसकी अच्छी व्याख्या है: en.cppreference.com/w/cpp/language/default_constructor
रिचर्ड

1
जहाँ तक मैं बता सकता हूँ, इन उदाहरणों में केवल C ++ 98 और C ++ 03 का अंतर है। यह समस्या N1161 में वर्णित है (उस दस्तावेज़ के बाद के संशोधन हैं) और CWG DR # 178शब्दों नई सुविधाओं और पॉड का एक नया विनिर्देश की वजह से सी ++ 11 में परिवर्तन करने की जरूरत है, और यह सी ++ 11 शब्दों में दोष के कारण सी ++ 14 में फिर से बदल दिया है, लेकिन इन मामलों में प्रभाव नहीं बदल रहे हैं ।
dyp

3
बोरिंग करते समय, struct D { D() {}; int m; };आपकी सूची में शामिल होने लायक हो सकता है।
यक्क - एडम नेवरामॉन्ट

जवाबों:


24

C ++ 14 new[expr.new] / 17 ([expr.new] / 15 में C ++ 11 के साथ बनाई गई वस्तुओं के आरंभीकरण को निर्दिष्ट करता है , और नोट तब नोट नहीं था, लेकिन फिर भी मानक पाठ वापस आ गया):

एक नई-अभिव्यक्ति जो प्रकार की एक वस्तु का निर्माण करती है, Tउस वस्तु को निम्न प्रकार से आरंभ करती है:

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

डिफ़ॉल्ट-आरंभीकरण को परिभाषित किया गया है [dcl.init] / 7 (/ 6 C ++ 11 में, और शब्दांकन का भी यही प्रभाव है):

किसी ऑब्जेक्ट के प्रकार को डिफ़ॉल्ट-प्रारंभ करना T:

  • यदि Tएक (संभवतः cv- योग्य) वर्ग प्रकार (क्लाज 9) है, तो डिफॉल्ट कंस्ट्रक्टर (12.1) Tको कॉल किया जाता है (और इनिशियलाइज़ेशन तब बनता है, जब Tकोई डिफॉल्ट कंस्ट्रक्टर या ओवरलोड रिज़ॉल्यूशन (13.3) न हो तो एक अस्पष्टता या परिणाम होता है एक फ़ंक्शन जिसे हटा दिया गया है या आरंभीकरण के संदर्भ से दुर्गम है);
  • यदि Tएक सरणी प्रकार है, तो प्रत्येक तत्व डिफ़ॉल्ट-आरंभिक है ;
  • अन्यथा, कोई प्रारंभ नहीं किया जाता है।

इस प्रकार

  • new Aपूरी तरह से As डिफॉल्ट कंस्ट्रक्टर को बुलाया जाता है, जो इनिशियलाइज़ नहीं करता है m। अनिश्चित मूल्य। के लिए समान होना चाहिए new B
  • new A() के अनुसार व्याख्या की जाती है [dcl.init] / 11 (/ C ++ 11 में 10):

    एक ऑब्जेक्ट जिसका इनिशलाइज़र कोष्ठक का एक खाली सेट है, अर्थात, ()मूल्य-इनिशियलाइज़ किया जाएगा।

    और अब विचार करें [dcl.init] / 8 (/ C ++ 11: में 7):

    एक वस्तु के प्रकार को महत्व देने के लिए T:

    • यदि Tकोई (संभवतः cv- योग्य) वर्ग प्रकार (क्लाज 9) है, जिसमें कोई डिफ़ॉल्ट कंस्ट्रक्टर (12.1) या डिफ़ॉल्ट कंस्ट्रक्टर नहीं है जो उपयोगकर्ता द्वारा प्रदान किया गया है या हटा दिया गया है, तो ऑब्जेक्ट डिफ़ॉल्ट-आरंभीकृत है;
    • यदि Tउपयोगकर्ता-प्रदान किए गए या हटाए गए डिफ़ॉल्ट निर्माता के बिना एक (संभवतः cv-योग्य) वर्ग प्रकार है, तो ऑब्जेक्ट शून्य-आरंभीकृत है और डिफ़ॉल्ट-आरंभीकरण के लिए सिमेंटिक अवरोधों की जाँच की जाती है, और यदि T में एक गैर-तुच्छ डिफ़ॉल्ट निर्माता है, ऑब्जेक्ट डिफ़ॉल्ट-आरंभीकृत है;
    • यदि Tएक सरणी प्रकार है, तो प्रत्येक तत्व मूल्य-आरंभिक है;
    • अन्यथा, ऑब्जेक्ट शून्य-प्रारंभिक है।

    इसलिए new A()जीरो-इनिशियल होगा m। और इस के लिए बराबर होना चाहिए Aऔर B

  • new Cऔर new C()ऑब्जेक्ट को फिर से डिफॉल्ट-इनिशियलाइज़ करेगा, क्योंकि अंतिम उद्धरण से पहला बुलेट पॉइंट लागू होता है (C में उपयोगकर्ता द्वारा प्रदान किया गया डिफॉल्ट कंस्ट्रक्टर है!)। लेकिन, स्पष्ट रूप से, अब mदोनों मामलों में कंस्ट्रक्टर में आरंभीकृत किया गया है।


† खैर, इस पैराग्राफ में C ++ 11 में थोड़ा अलग शब्दांकन है, जो परिणाम में परिवर्तन नहीं करता है:

एक वस्तु के प्रकार को महत्व देने के लिए T:

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

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

आह तो आप मुख्य रूप से c ++ 14 के बारे में बात कर रहे हैं और c ++ 11 के संदर्भ कोष्ठक में दिए गए हैं
गेब्रियल

@ गैब्रिएल सही। मेरा मतलब है, सी ++ 14 नवीनतम मानक है, इसलिए यह सामने है।
कोलम्बो

1
मानकों पर आरंभीकरण नियमों का पता लगाने की कोशिश करने के बारे में कष्टप्रद बात यह है कि प्रकाशित C ++ 14 और C ++ 11 मानकों के बीच बहुत सारे परिवर्तन (अधिकांश सभी?) DR के माध्यम से हुए हैं, और इसलिए वास्तव में C ++ 11 हैं । और फिर पोस्ट-सी ++ 14 डीआर भी हैं ...
टीसी

@ कोलुम्बो मुझे अभी भी समझ में नहीं आता है कि struct A { int m; }; struct C { C() : m(){}; int m; };अलग-अलग परिणाम क्यों आते हैं और पहली बार में एम को ए में शुरू करने का क्या कारण है। मैंने प्रयोग के लिए एक समर्पित धागा खोला है और मैंने इस मुद्दे को स्पष्ट करने के लिए आपके इनपुट की सराहना की है। धन्यवाद stackoverflow.com/questions/45290121/…
DarkThoughts

12

निम्नलिखित उत्तर https://stackoverflow.com/a/620402/977038 उत्तर का विस्तार करता है जो C ++ 98 और C ++ 03 के लिए एक संदर्भ के रूप में काम करेगा।

उत्तर का हवाला देते हुए

  1. C ++ 1998 में प्रारंभ के 2 प्रकार हैं: शून्य और डिफ़ॉल्ट
  2. C ++ 2003 में एक 3 प्रकार के आरंभीकरण, मूल्य आरंभीकरण जोड़ा गया था।

C ++ 11 (n3242 के संदर्भ में)

initializers

8.5 initializers [dcl.init] निर्दिष्ट करता है कि एक चर पॉड या गैर पॉड के रूप में या तो प्रारंभ किया जा सकता है ब्रेस या बराबर-प्रारंभकर्ता जो या तो किया जा सकता है braced-init-सूची या प्रारंभकर्ता-खंड aggregately रूप में जाना जाता ब्रेस या equal- initializer या उपयोग (अभिव्यक्ति-सूची) । C ++ 11 से पहले, केवल (अभिव्यक्ति-सूची) या initializer-खंड को समर्थन दिया गया था, हालांकि initializer-clause अधिक प्रतिबंधित था फिर C ++ 11 में हमारे पास क्या है। C ++ 11 में, इनिशियलाइज़र-क्लॉज अब असाइनमेंट-एक्सप्रेशन के अलावा ब्रेडेड-इन-लिस्ट को सपोर्ट करता हैजैसा कि C ++ 03 में था। निम्नलिखित व्याकरण नए समर्थित खंड को सारांशित करता है, जहां भाग बोल्ड होता है जिसे C ++ 11 मानक में जोड़ा जाता है।

initializer:
    brace-or-initial-initializer
    (एक्सप्रेशन-लिस्ट)
brace-or-equal-initial-initializer:
    = initializer-clause
    braced-init-list
इनिशियलाइज़र-क्लॉज:
    असाइनमेंट-एक्सप्रेशन
    -ब्रेस्ड-इनिट-लिस्ट
initializer-list:
    initializer-clause ... ऑप्टिमाइज़र -सूची ऑप्टिमाइज़र
    -क्लॉज़ ... ऑप्ट **
लट-इन-सूची-सूची:
    {इनिशियलाइज़र-सूची, ऑप्ट}
    }}

प्रारंभ

C ++ 03 की तरह, C ++ 11 अभी भी प्रारंभ के तीन रूप का समर्थन करता है


ध्यान दें

बोल्ड में हाइलाइट किए गए भाग को C ++ 11 में जोड़ा गया है और जो स्ट्राइक आउट किया गया है उसे C ++ 11 से हटा दिया गया है।

  1. प्रारंभिक प्रकार: 8.5.5 [dcl.init] _zero-initialize_

निम्नलिखित मामलों में प्रदर्शन किया

  • स्थिर या थ्रेड स्टोरेज अवधि वाली वस्तुएं शून्य-आरंभिक हैं
  • यदि सरणी तत्व कम से कम प्रारंभिक हैं, तो प्रत्येक तत्व जो स्पष्ट रूप से आरंभिक नहीं है, उन्हें शून्य-प्रारंभिक किया जाएगा
  • वैल्यू-इनिशियलाइज़ करने के दौरान , यदि T एक (संभवतः cv-योग्य) नॉन-यूनियन क्लास प्रकार है, जो किसी उपयोगकर्ता द्वारा प्रदान किए गए कंस्ट्रक्टर के बिना है, तो ऑब्जेक्ट शून्य-इनिशियलाइज़ेड है।

किसी वस्तु को टाइप-टी के संदर्भ को शून्य-प्रारंभिक करना

  • यदि T एक अदिश प्रकार (3.9) है, तो ऑब्जेक्ट को मान 0 पर सेट किया जाता है (शून्य), एक अभिन्न स्थिर अभिव्यक्ति के रूप में लिया जाता है , जिसे T में परिवर्तित किया जाता है;
  • यदि T एक (संभवतः cv-योग्य) गैर-यूनियन वर्ग प्रकार है, तो प्रत्येक गैर-स्थैतिक डेटा सदस्य और प्रत्येक बेस-क्लास सबोबेज शून्य-आरंभिक है और पैडिंग शून्य बिट्स के लिए आरंभिक है;
  • यदि T एक (संभवतः cv-योग्य) यूनियन प्रकार है, तो ऑब्जेक्ट का पहला गैर-स्थिर नाम डेटा सदस्य शून्य इनिशियलाइज़्ड है और पैडिंग शून्य बिट्स के लिए आरंभीकृत है;
  • यदि T एक सरणी प्रकार है, तो प्रत्येक तत्व शून्य-आरंभीकृत है;
  • यदि T एक संदर्भ प्रकार है, तो कोई प्रारंभ नहीं किया जाता है।

2. प्रारंभिक प्रकार: 8.5.6 [dcl.init] _default-initialize_

निम्नलिखित मामलों में प्रदर्शन किया

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

डिफ़ॉल्ट का प्रकार टी के एक वस्तु का मतलब प्रारंभिक:

  • यदि T एक (संभवतः cv-योग्य) गैर-POD वर्ग प्रकार (क्लाज 9) है, तो T के लिए डिफॉल्ट कंस्ट्रक्टर को बुलाया जाता है (और यदि टी का कोई डिफॉल्ट डिफॉल्ट कंस्ट्रक्टर नहीं है, तो इनिशियलाइज़ेशन बीमार हो जाता है);
  • यदि T एक सरणी प्रकार है, तो प्रत्येक तत्व डिफ़ॉल्ट-आरंभिक है;
  • अन्यथा, कोई प्रारंभ नहीं किया जाता है।

नोट जब तक C ++ 11, केवल गैर-POD वर्ग प्रकार जो स्वचालित संग्रहण अवधि के साथ डिफ़ॉल्ट-आरंभिक माना जाता था, जब कोई initializer का उपयोग नहीं किया जाता है।


3. प्रारंभिक प्रकार: 8.5.7 [dcl.init] _value-initialize_

  1. जब कोई ऑब्जेक्ट (नामांकित अस्थायी, नामित चर, गतिशील भंडारण अवधि या गैर-स्थैतिक डेटा सदस्य) जिसका इनिशलाइज़र कोष्ठक का खाली सेट है, () (या ब्रेसिज़ {}

टी प्रकार की एक वस्तु को महत्व देने के लिए इसका मतलब है:

  • यदि T एक (संभवतः cv-योग्य) वर्ग प्रकार (क्लाज 9) है जो एक उपयोगकर्ता द्वारा प्रदान किए गए कंस्ट्रक्टर (12.1) के साथ है, तो T के लिए डिफ़ॉल्ट कंस्ट्रक्टर को बुलाया जाता है (और यदि टी का कोई सुलभ डिफॉल्ट कंस्ट्रक्टर नहीं है तो इनिशियलाइज़ेशन बीमार हो जाता है) ;
  • यदि T उपयोगकर्ता-प्रदान किए गए निर्माता के बिना एक (संभवतः cv-योग्य) गैर-यूनियन वर्ग प्रकार है, तो T के प्रत्येक गैर-स्थैतिक डेटा सदस्य और बेस-क्लास घटक का मूल्य-प्रारंभिक है; तब ऑब्जेक्ट शून्य-आरंभीकृत होता है और, यदि टी के अंतर्निहित घोषित डिफ़ॉल्ट निर्माता गैर-तुच्छ हैं, तो उस निर्माता को कहा जाता है।
  • यदि T एक सरणी प्रकार है, तो प्रत्येक तत्व मूल्य-आरंभिक है;
  • अन्यथा, ऑब्जेक्ट शून्य-प्रारंभिक है।

इसलिए संक्षेप में

नोट मानक से प्रासंगिक उद्धरण बोल्ड में हाइलाइट किया गया है

  • नया A: डिफ़ॉल्ट-इनिशियलाइज़ (A: m uninitialized छोड़ता है)
  • नया A (): शून्य-आरंभिक A, क्योंकि मूल्य आरंभीकृत उम्मीदवार के पास उपयोगकर्ता-प्रदान या हटाए गए डिफ़ॉल्ट निर्माणकर्ता नहीं है। यदि टी एक (संभवतः cv-योग्य) उपयोगकर्ता-प्रदान किए गए निर्माता के बिना गैर-यूनियन वर्ग प्रकार है, तो ऑब्जेक्ट शून्य-आरंभीकृत है और, यदि टी के अंतर्निहित घोषित डिफ़ॉल्ट गैर-तुच्छ है, तो उस निर्माता को कहा जाता है।
  • नया B: डिफ़ॉल्ट-इनिशियलाइज़
  • new B (): value-initializes B जो शून्य-सभी क्षेत्रों को इनिशियलाइज़ करता है; यदि T एक (संभवतः cv-योग्य) वर्ग प्रकार (क्लाज 9) है जो एक उपयोगकर्ता द्वारा प्रदान किए गए कंस्ट्रक्टर (12.1) के साथ है, तो T के लिए डिफ़ॉल्ट कंस्ट्रक्टर को कहा जाता है
  • new C: default-initializes C, जिसे डिफ़ॉल्ट ctor कहता है। यदि T एक (संभवतः cv-योग्य) वर्ग प्रकार (क्लाज 9) है, तो T के लिए डिफ़ॉल्ट कंस्ट्रक्टर को कॉल किया जाता है , इसके अलावा यदि नया-इनिशियलाइज़र छोड़ा गया है, तो ऑब्जेक्ट डिफ़ॉल्ट-इनिशियलाइज़्ड है
  • नया C (): C को वैल्यू इनिशियलाइज़ करता है, जो डिफॉल्ट ctor को कॉल करता है। यदि T एक (संभवतः cv- योग्य) वर्ग प्रकार (क्लाज 9) है जो एक उपयोगकर्ता द्वारा प्रदान किए गए कंस्ट्रक्टर (12.1) के साथ है, तो T के लिए डिफ़ॉल्ट कंस्ट्रक्टर को कहा जाता है। इसके अलावा, एक ऑब्जेक्ट जिसका इनिशलाइज़र कोष्ठकों का एक खाली सेट है, अर्थात (), का मूल्य-इनिशियलाइज़ किया जाएगा

0

मैं पुष्टि कर सकता हूं कि C ++ 11 में, C ++ 14 के तहत प्रश्न में उल्लिखित सब कुछ सही है, कम से कम संकलक कार्यान्वयन के अनुसार।

इसे सत्यापित करने के लिए, मैंने निम्नलिखित कोड को अपने परीक्षण सूट में जोड़ा । मैंने -std=c++11 -O3जीसीसी 7.4.0, जीसीसी 5.4.0, क्लेंग 10.0.1, और वीएस 2017 के साथ परीक्षण किया, और नीचे दिए गए सभी परीक्षण।

#include <gtest/gtest.h>
#include <memory>

struct A { int m;                    };
struct B { int m;            ~B(){}; };
struct C { int m; C():m(){}; ~C(){}; };
struct D { int m; D(){};             };
struct E { int m; E() = default;     };
struct F { int m; F();               }; F::F() = default;

// We use this macro to fill stack memory with something else than 0.
// Subsequent calls to EXPECT_NE(a.m, 0) are undefined behavior in theory, but
// pass in practice, and help illustrate that `a.m` is indeed not initialized
// to zero. Note that we initially tried the more aggressive test
// EXPECT_EQ(a.m, 42), but it didn't pass on all compilers (a.m wasn't equal to
// 42, but was still equal to some garbage value, not zero).
//
#define FILL { int m = 42; EXPECT_EQ(m, 42); }

// We use this macro to fill heap memory with something else than 0, before
// doing a placement new at that same exact location. Subsequent calls to
// EXPECT_EQ(a->m, 42) are undefined behavior in theory, but pass in practice,
// and help illustrate that `a->m` is indeed not initialized to zero.
//
#define FILLH(b) std::unique_ptr<int> bp(new int(42)); int* b = bp.get(); EXPECT_EQ(*b, 42)

TEST(TestZero, StackDefaultInitialization)
{
    { FILL; A a; EXPECT_NE(a.m, 0); } // UB!
    { FILL; B a; EXPECT_NE(a.m, 0); } // UB!
    { FILL; C a; EXPECT_EQ(a.m, 0); }
    { FILL; D a; EXPECT_NE(a.m, 0); } // UB!
    { FILL; E a; EXPECT_NE(a.m, 0); } // UB!
    { FILL; F a; EXPECT_NE(a.m, 0); } // UB!
}

TEST(TestZero, StackValueInitialization)
{
    { FILL; A a = A(); EXPECT_EQ(a.m, 0); }
    { FILL; B a = B(); EXPECT_EQ(a.m, 0); }
    { FILL; C a = C(); EXPECT_EQ(a.m, 0); }
    { FILL; D a = D(); EXPECT_NE(a.m, 0); } // UB!
    { FILL; E a = E(); EXPECT_EQ(a.m, 0); }
    { FILL; F a = F(); EXPECT_NE(a.m, 0); } // UB!
}

TEST(TestZero, StackListInitialization)
{
    { FILL; A a{}; EXPECT_EQ(a.m, 0); }
    { FILL; B a{}; EXPECT_EQ(a.m, 0); }
    { FILL; C a{}; EXPECT_EQ(a.m, 0); }
    { FILL; D a{}; EXPECT_NE(a.m, 0); } // UB!
    { FILL; E a{}; EXPECT_EQ(a.m, 0); }
    { FILL; F a{}; EXPECT_NE(a.m, 0); } // UB!
}

TEST(TestZero, HeapDefaultInitialization)
{
    { FILLH(b); A* a = new (b) A; EXPECT_EQ(a->m, 42); } // ~UB
    { FILLH(b); B* a = new (b) B; EXPECT_EQ(a->m, 42); } // ~UB
    { FILLH(b); C* a = new (b) C; EXPECT_EQ(a->m, 0);  }
    { FILLH(b); D* a = new (b) D; EXPECT_EQ(a->m, 42); } // ~UB
    { FILLH(b); E* a = new (b) E; EXPECT_EQ(a->m, 42); } // ~UB
    { FILLH(b); F* a = new (b) F; EXPECT_EQ(a->m, 42); } // ~UB
}

TEST(TestZero, HeapValueInitialization)
{
    { FILLH(b); A* a = new (b) A(); EXPECT_EQ(a->m, 0);  }
    { FILLH(b); B* a = new (b) B(); EXPECT_EQ(a->m, 0);  }
    { FILLH(b); C* a = new (b) C(); EXPECT_EQ(a->m, 0);  }
    { FILLH(b); D* a = new (b) D(); EXPECT_EQ(a->m, 42); } // ~UB
    { FILLH(b); E* a = new (b) E(); EXPECT_EQ(a->m, 0);  }
    { FILLH(b); F* a = new (b) F(); EXPECT_EQ(a->m, 42); } // ~UB
}

TEST(TestZero, HeapListInitialization)
{
    { FILLH(b); A* a = new (b) A{}; EXPECT_EQ(a->m, 0);  }
    { FILLH(b); B* a = new (b) B{}; EXPECT_EQ(a->m, 0);  }
    { FILLH(b); C* a = new (b) C{}; EXPECT_EQ(a->m, 0);  }
    { FILLH(b); D* a = new (b) D{}; EXPECT_EQ(a->m, 42); } // ~UB
    { FILLH(b); E* a = new (b) E{}; EXPECT_EQ(a->m, 0);  }
    { FILLH(b); F* a = new (b) F{}; EXPECT_EQ(a->m, 42); } // ~UB
}

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

जिन स्थानों UB!का उल्लेख किया गया है, वे अपरिभाषित व्यवहार हैं, और वास्तविक व्यवहार कई कारकों पर निर्भर होने की संभावना है ( a.m42, 0 या कुछ अन्य कचरा के बराबर हो सकता है)। जिन स्थानों ~UBका उल्लेख किया गया है, वे भी सिद्धांत में अपरिभाषित व्यवहार हैं, लेकिन व्यवहार में, एक प्लेसमेंट नए के उपयोग के कारण, यह a->m42 की तुलना में किसी भी चीज़ के बराबर नहीं होगा।

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