2015-05-27 6 views
7

मैं एक कस्टम संस्करण प्रकार को लागू करने की कोशिश कर रहा हूं जो विभिन्न प्रकार के डेटा स्टोर करने के लिए यूनियन का उपयोग करता है। क्षेत्र में type_id मैं स्टोर करने की योजना बना रहा हूं कि यूनियन में संग्रहीत डेटा किस प्रकार का है। संघ में गैर-तुच्छ सदस्य हैं।गैर-तुच्छ सदस्यों के साथ यूनियन युक्त वर्ग के लिए कन्स्ट्रक्टर और कॉपी-कन्स्ट्रक्टर

struct MyVariant { 
    enum { t_invalid, t_string, t_int, t_double, t_ptr, t_dictionary } type_id; 
    union { 
    int        as_int; 
    double       as_double; 
    std::string      as_string; 
    std::unique_ptr<int>   as_ptr; 
    std::map<int, double>   as_dictionary; 
    }; 
}; 

मैं की MyVariant तरह एक उदाहरण बनाने की कोशिश इस प्रकार है:: कॉल MyVariant की परोक्ष हटाए डिफ़ॉल्ट निर्माता रहे हैं:

MyVariant v; 

मैं त्रुटि संदेश मिलता है यहाँ मेरे वर्तमान कार्यान्वयन है। तो, मैं निर्माता मैन्युअल लागू करना चाहते करने की कोशिश की इस प्रकार है:

MyVariant() : type_id{t_int}, as_int{0} {} 

जो मुझे देता है एक ऐसी ही त्रुटि संदेश: किसी हटाए समारोह उपयोग करने के लिए प्रयास।

MyVariant(int value) : type_id{t_int}, as_int{value} {} 

और मेरे उदाहरण का निर्माण इस प्रकार की तरह: इसके बाद, मैं निम्नलिखित निर्माता को लागू करने की कोशिश की

MyVariant v{123}; 

=> एक ही त्रुटि संदेश: किसी हटाए समारोह उपयोग करने के लिए प्रयास।

मैंने एक कॉपी कन्स्ट्रक्टर को भी लागू करना शुरू कर दिया है, ऐसा लगता है। हालांकि, निश्चित रूप से यह संकलक त्रुटियों में मदद नहीं करता है।

MyVariant::MyVariant(const MyVariant& other) 
{ 
    type_id = other.type_id; 
    switch (type_id) { 
     case t_invalid: 
      break; 
     case t_string: 
      new (&as_string) std::string(); 
      as_string = other.as_string; 
      break; 
     case t_int: 
      as_int = other.as_int; 
      break; 
     case t_double: 
      as_double = other.as_double; 
      break; 
     case t_ptr: 
      new (&as_ptr) std::unique_ptr<int>(nullptr); 
      as_ptr = std::make_unique<int>(*other.as_ptr); 
      break; 
     case t_dictionary: 
      new (&as_dictionary) std::map<int, double>(); 
      // TODO: copy values from other 
      break; 
    } 
} 

मैं संकलक के रूप में एक्सकोड और ऐप्पल एलएलवीएम 6.1 का उपयोग कर रहा हूं।

मुख्य प्रश्न यह है कि: मुझे संकलक त्रुटियां क्यों मिलती हैं जो मुझे मिल रही हैं और इसे संकलित करने के लिए मुझे अपने कोड को कैसे संशोधित करना है?

अतिरिक्त प्रश्न यह है: क्या मैं कन्स्ट्रक्टर और कॉपी कन्स्ट्रक्टर के लिए मेरे कार्यान्वयन के साथ सही तरीके से हूं?

+0

वह डिफ़ॉल्ट कन्स्ट्रक्टर ठीक है। आपको एक विनाशक को लागू करने की आवश्यकता है। –

+0

क्या आपका मतलब माता-पिता के बजाय ब्रेसिज़ का उपयोग करना था जहां आपका एक उदाहरण आवंटित किया गया था? – donjuedo

+0

@donjuedo हां, मेरा मतलब ब्रेसिज़ का उपयोग करना था क्योंकि मैं वर्दी सी ++ 11 प्रारंभिक वाक्यविन्यास से चिपकना चाहता हूं। क्या उनके साथ कुछ गलत है? – j00hi

उत्तर

7

आपका संघ प्रकार string, unique_ptr और map, जो सभी गैर तुच्छ डिफ़ॉल्ट/कॉपी/स्थानांतरित कंस्ट्रक्टर्स, कॉपी/कदम असाइनमेंट ऑपरेटरों और विनाशकर्ता है डेटा सदस्य हैं। इसलिए इन सभी को आपके संघ के लिए पूरी तरह से हटा दिया गया है।

§9.5/2 [class.union]

... [नोट: एक संघ के किसी भी गैर स्थैतिक डेटा सदस्य एक गैर तुच्छ डिफ़ॉल्ट निर्माता नहीं हैं (12.1) , प्रतिलिपि कन्स्ट्रक्टर (12.8), कन्स्ट्रक्टर (12.8), कॉपी असाइनमेंट ऑपरेटर (12.8), असाइनमेंट ऑपरेटर (12.8), या विनाशक (12.4) ले जाएं, संबंधित यूनियन के सदस्य फ़ंक्शन उपयोगकर्ता द्वारा प्रदत्त होना चाहिए या यह होगा संघ के लिए पूरी तरह से हटा दिया गया (8.4.3)। -end नोट]

तो आपको इन्हें अपने संघ के लिए मैन्युअल रूप से कार्यान्वित करना होगा। कम से कम, आप MyVariant का उदाहरण बनाने में सक्षम होने के लिए, कक्षा को रचनात्मक और विनाशकारी होना चाहिए।तो अगर आप की जरूरत है

MyVariant() : type_id{t_int}, as_int{0} {} 
~MyVariant() 
{ 
    switch(type_id) 
    { 
     case t_int: 
     case t_double: 
     // trivially destructible, no need to do anything 
     break; 
     case t_string: 
     as_string.~basic_string(); 
     break; 
     case t_ptr: 
     as_ptr.~unique_ptr(); 
     break; 
     case t_dictionary: 
     as_dictionary.~map(); 
     break; 
     case t_invalid: 
     // do nothing 
     break; 
     default: 
     throw std::runtime_error("unknown type"); 
    } 
} 

आपकी प्रतिलिपि निर्माता कार्यान्वयन वैध है, लेकिन मैं क्या अलग करना चाहते हैं पहले डिफ़ॉल्ट सदस्य के निर्माण, और फिर स्रोत ऑब्जेक्ट से कॉपी करके, बस कॉपी नियुक्ति में निर्माण के बजाय है नया ही फोन ।

MyVariant(const MyVariant& other) 
{ 
    type_id = other.type_id; 
    switch (type_id) { 
     case t_invalid: 
      break; 
     case t_string: 
      new (&as_string) auto(other.as_string); 
      break; 
     case t_int: 
      as_int = other.as_int; 
      break; 
     case t_double: 
      as_double = other.as_double; 
      break; 
     case t_ptr: 
      new (&as_ptr) auto(std::make_unique<int>(*other.as_ptr)); 
      break; 
     case t_dictionary: 
      new (&as_dictionary) auto(other.as_dictionary); 
      break; 
    } 

Live demo

ध्यान दें कि यदि unique_ptr सदस्य सक्रिय है, और एक आधार वर्ग सूचक के माध्यम से कुछ व्युत्पन्न वर्ग उदाहरण के लिए सूचक भंडारण है, तो आपके प्रति निर्माता कार्यान्वयन केवल आधार वर्ग हिस्सा कॉपी कर देंगे।

अंत में, जब तक कि आप इसे सीखने के अभ्यास के रूप में नहीं कर रहे हैं, तो मैं दृढ़ता से आग्रह करता हूं कि आप अपना खुद का रोलिंग करने के बजाय Boost.Variant का उपयोग करें।

+3

टिडबिट: 'नया (& as_dictionary) ऑटो (अन्य.एएस_डिर्नी)' और इसी तरह कुछ अनावश्यकता से छुटकारा पा सकता है, और यह अधिक रिफैक्टरिंग अनुकूल है। –

+0

Boost.Variant C++ की वर्तमान स्थिति के लिए काफी पुराना है। – Orient

+0

@ ओरीन्ट आपको क्यों लगता है, बूस्ट.वंटन पुराना है? और इसके लिए एक अच्छा, आधुनिक विकल्प क्या होगा? – j00hi

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