2008-11-26 15 views
40

के साथ एक संघ शुरू करना मेरे पास एक संरचना है जिसे मैं सदस्यों को 0 के प्रारंभ करने के लिए एक कस्टम कन्स्ट्रक्टर बनाता हूं। मैंने पुराने कंपाइलर्स में देखा है कि रिलीज मोड में, 0 को मेमसेट किए बिना, मान प्रारंभ नहीं किए जाते हैं।एक गैर-तुच्छ कन्स्ट्रक्टर

अब मैं इस संरचना का उपयोग संघ में करना चाहता हूं, लेकिन त्रुटियां प्राप्त करें क्योंकि इसमें एक गैर-तुच्छ कन्स्ट्रक्टर है।

तो, प्रश्न 1. क्या डिफ़ॉल्ट कंपाइलर ने कन्स्ट्रक्टर को लागू किया है कि संरचना के सभी सदस्यों को शुरू किया जाएगा? गैर-तुच्छ कन्स्ट्रक्टर केवल स्वच्छ संरचना सुनिश्चित करने के लिए सभी सदस्यों की यादों को '0' पर करता है।

प्रश्न 2: यदि आधार संरचना पर एक निर्माता को निर्दिष्ट किया जाना चाहिए, तो उस तत्व को शामिल करने के लिए एक संघ को कैसे लागू किया जा सकता है और 0 प्रारंभिक आधार तत्व सुनिश्चित किया जा सकता है?

उत्तर

40

प्रश्न 1: डिफ़ॉल्ट निर्माता पीओडी सदस्यों को सी ++ मानक के अनुसार 0 में प्रारंभ करते हैं। नीचे उद्धृत पाठ देखें।

प्रश्न 2: यदि किसी श्रेणी में एक निर्माता को निर्दिष्ट किया जाना चाहिए, तो वह वर्ग संघ का हिस्सा नहीं हो सकता है।

अंत में, आप अपने संघ के लिए एक निर्माता प्रदान कर सकते हैं:

union U 
{ 
    A a; 
    B b; 

    U() { memset(this, 0, sizeof(U)); } 
}; 

Q1 के लिए:

से सी ++ 03, 12.1 कंस्ट्रक्टर्स, स्नातकोत्तर 190

परोक्ष परिभाषित डिफ़ॉल्ट निर्माता कक्षा के प्रारंभिकरण के सेट को निष्पादित करता है जो उस वर्ग के लिए एक खाली ज्ञापन-प्रारंभकर्ता-सूची (12.6.2) और खाली फ़ंक्शन बॉडी के साथ उपयोगकर्ता द्वारा लिखित डिफ़ॉल्ट कन्स्ट्रक्टर द्वारा किया जाएगा।

सी ++ 03, 8 से।5 initializers, स्नातकोत्तर 145

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

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

के प्रकार टी का एक उद्देश्य शून्य से प्रारंभ का अर्थ है:

  • अगर टी एक अदिश प्रकार (3.9), वस्तु 0 (शून्य) के मान पर सेट है टी में बदल जाती है,
  • अगर टी एक गैर संघ वर्ग प्रकार, प्रत्येक गैर स्थिर डेटा सदस्य और प्रत्येक आधार स्तरीय subobject है शून्य प्रारंभ है;
  • अगर टी एक संघ प्रकार है, वस्तु की पहली नामित डेटा सदस्य शून्य से आरंभ होता है;
  • अगर टी एक सरणी प्रकार है, प्रत्येक तत्व शून्य से आरंभ होता है;
  • यदि टी एक संदर्भ प्रकार है, तो कोई प्रारंभिकता नहीं की जाती है।

Q2 के लिए:

से सी ++ 03, 12.1 कंस्ट्रक्टर्स, स्नातकोत्तर 190

एक निर्माता तुच्छ है अगर यह एक परोक्ष-घोषित डिफ़ॉल्ट निर्माता है और यदि:

  • अपने वर्ग कोई आभासी कार्यों (10.3) और कोई आभासी आधार वर्ग (10.1), और
  • सभी प्रत्यक्ष आधार अपने वर्ग की कक्षाएं तुच्छ कंस्ट्रक्टर्स है है, और
  • उस वर्ग प्रकार (या सरणी क्या है) के हैं अपने वर्ग के सभी nonstatic डेटा सदस्यों के लिए, ऐसे प्रत्येक वर्ग एक छोटी सी निर्माता

है सी ++ 03, 9.5 यूनियन, स्नातकोत्तर 162

से

एक संघ में सदस्य कार्य (कन्स्ट्रक्टर और विनाशक समेत) हो सकते हैं, लेकिन वर्चुअल (10.3) फ़ंक्शन नहीं। एक संघ के पास बेस क्लास नहीं होंगे। एक संघ को आधार वर्ग के रूप में उपयोग नहीं किया जाएगा। एक गैर-तुच्छ कन्स्ट्रक्टर (12.1) के साथ एक वर्ग की एक वस्तु, एक गैर-तुच्छ प्रतिलिपि निर्माता (12.8), एक गैर-तुच्छ विनाशक (12.4), या एक गैर-तुच्छ कॉपी असाइनमेंट ऑपरेटर (13.5.3, 12.8) यूनियन का सदस्य नहीं हो सकता है, न ही ऐसी वस्तुओं की एक सरणी

+21

यहां क्या गुम है कि नाम के बावजूद, डिफ़ॉल्ट निर्माता डिफ़ॉल्ट नहीं हैं-पीओडी सदस्यों को प्रारंभ करें। 12.6.2/4 कहता है कि क्या होता है जब किसी प्रारंभिक सूची में किसी सदस्य का उल्लेख नहीं किया जाता है, और 12.1 से आपके उद्धरण के द्वारा, यह अंतर्निहित ctors पर लागू होता है। यह कहता है, "यदि इकाई का एक गैर स्थैतिक डेटा सदस्य है ... वर्ग प्रकार ... और इकाई वर्ग एक गैर-पीओडी वर्ग है, तो इकाई डिफ़ॉल्ट-प्रारंभिक है ... अन्यथा, इकाई प्रारंभ नहीं की गई है "। इसलिए, पीओडी डेटा सदस्यों को अंतर्निहित जनरेटेड कन्स्ट्रक्टर द्वारा प्रारंभ नहीं किया जाता है। गैर-पीओडी डेटा सदस्य डिफ़ॉल्ट-प्रारंभिक हैं। –

+2

यह उत्तर पुराना है .. –

0

क्या आप ऐसा कुछ कर सकते हैं?

class Outer 
{ 
public: 
    Outer() 
    { 
     memset(&inner_, 0, sizeof(inner_)); 
    } 
private: 
    union Inner 
    { 
     int qty_; 
     double price_; 
    } inner_; 
}; 

... या शायद ऐसा कुछ हो सकता है?

union MyUnion 
{ 
    int qty_; 
    double price_; 
}; 

void someFunction() 
{ 
    MyUnion u = {0}; 
} 
+0

हमने इसे माना था, लेकिन जिस संरचना को हमने संघ में डालने का प्रयास किया है वह कोड के अन्य हिस्सों में उपयोग में है, इसलिए कन्स्ट्रक्टर को हटा रहा है (माना जाता है कि संकलक पीओडी के रूप में संरचना का व्यवहार करता है और सभी तत्वों को 0 से इंटिलाइज नहीं करता है) कोड तोड़ सकता है जो उस पर निर्भर करता है। – Superpolock

3

AFAIK संघ के सदस्यों में रचनाकार या विनाशक नहीं हो सकते हैं।

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

गैर-पीओडी सदस्य हमेशा उनके डिफ़ॉल्ट कन्स्ट्रक्टर के माध्यम से बनाए जाएंगे, जो संश्लेषित किए जाने पर, पीओडी-सदस्यों को फिर से शुरू नहीं करेंगे। यह देखते हुए कि संघ के सदस्यों के पास रचनाकार नहीं हो सकते हैं, आपको बहुत अधिक गारंटी होगी कि एक संघ में structs के पीओडी-सदस्यों को शुरू नहीं किया जाएगा।

प्रश्न 2: आप हमेशा संरचनाओं/यूनियनों को प्रारंभ कर सकते हैं ताकि तरह:

struct foo 
{ 
    int a; 
    int b; 
}; 

union bar 
{ 
    int a; 
    foo f; 
}; 

bar b = { 0 }; 
+2

आप यूनियन को स्वयं एक निर्माता बना सकते हैं जो स्मृति को स्वयं शून्य पर दे सकता है। –

+0

अच्छा बिंदु! मैं यूनियन रचनाकारों के बारे में भूल रहा हूं! –

+1

किसी प्रोग्रामर डिफ़ॉल्ट कन्स्ट्रक्टर के बीच कोई प्रारंभिक सूची और खाली निकाय और संकलक उत्पन्न कन्स्ट्रक्टर के बीच कोई अंतर नहीं है। –

-1

आप होगा के लिए C++ 0x compilers द्वारा समर्थित होने की इस पाने के लिए प्रतीक्षा करने के लिए। तब तक, क्षमा करें।

2

जैसा कि ग्रेग रोजर्स की टिप्पणी unwesen की पोस्ट पर उल्लिखित है, आप अपने संघ को एक कन्स्ट्रक्टर दे सकते हैं (और नाशक यदि आप चाहें):

struct foo 
{ 
    int a; 
    int b; 
}; 

union bar 
{ 
    bar() { memset(this, 0, sizeof(*this)); } 

    int a; 
    foo f; 
}; 
+0

से नीचे C++ 11 के लिए मेरा उत्तर देखें जैसे मुझे कुछ शिक्षा चाहिए। ऑब्जेक्ट को शून्य पर याद नहीं करेगा, कक्षा वर्चुअल तालिका को मिटा दें? – EvilTeach

+4

@EvilTeach, दो चीजें, 1) आपको पॉलिमॉर्फिज्म को लागू करने के लिए एक vtable का उपयोग करने की आवश्यकता नहीं है (सभी को छोड़कर)। 2) क्या आप foo पर कोई वर्चुअल विधियां देखते हैं? या उस मामले के लिए बिल्कुल कोई तरीका? क्या यह किसी भी चीज़ से प्राप्त होता है? आभासी तरीकों के बिना कोई vtable नहीं है। वास्तव में, वर्चुअल विधियों के लिए foo थे और एक vtable विस्तार से यह अब एक पीओडी नहीं होगा, और इसलिए संघ में सदस्यता के लिए अपात्र। –

22

हालात सी ++ 11 में बेहतर करने के लिए बदल दिया है।

अब आप कानूनी रूप से ऐसा कर सकते हैं, described by Stroustrup स्वयं (मैं Wikipedia article on C++11 से उस लिंक पर पहुंच गया)।

#include <new> // Required for placement 'new'. 

struct Point { 
    Point() {} 
    Point(int x, int y): x_(x), y_(y) {} 
    int x_, y_; 
}; 

union U { 
    int z; 
    double w; 
    Point p; // Illegal in C++03; legal in C++11. 
    U() {new(&p) Point();} // Due to the Point member, a constructor 
          // definition is now *required*. 
}; 

Stroustrup थोड़ा और विस्तार में चला जाता है:

विकिपीडिया पर उदाहरण इस प्रकार है।

+0

यह विजुअल स्टूडियो (2013) – maja

+0

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

+0

@Yttrill जबकि यह सच है कि आपको एक निर्माता को परिभाषित करने की आवश्यकता नहीं है जब तक कि आप 'यू' का उदाहरण नहीं बनाते, मुझे विश्वास नहीं है कि संघ के किसी भी सदस्य तक पहुंचने के लिए 'यू *' का उपयोग करना कानूनी है यदि कोई संघ नहीं वस्तु का निर्माण किया गया है। [basic.life] _B किसी ऑब्जेक्ट के जीवनकाल से पहले शुरू हो गया है लेकिन ऑब्जेक्ट पर कब्जा करने वाले भंडारण के बाद आवंटित किया गया है [...] किसी भी सूचक जो भंडारण स्थान को संदर्भित करता है [...] को संदर्भित किया जा सकता है लेकिन .. ।]। कार्यक्रम में व्यवहार को अपरिभाषित किया गया है यदि [...] पॉइंटर का उपयोग गैर-स्थैतिक डेटा सदस्य तक पहुंचने के लिए किया जाता है या ऑब्जेक्ट_ – davmac

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