2008-12-29 18 views
7

सी ++ में प्रत्येक कुंजी के लिए मनमानी मूल्य प्रकारों के साथ एक सहयोगी सरणी रखने का सबसे अच्छा तरीका क्या है?मूल्यों के लिए मनमानी प्रकारों के साथ सी ++ एसोसिएटिव सरणी

वर्तमान में मेरी योजना उन प्रकारों के सदस्य चर के साथ "मूल्य" वर्ग बनाना है जो मैं उम्मीद करूँगा। उदाहरण के लिए:

class Value { 

    int iValue; 
    Value(int v) { iValue = v; } 

    std::string sValue; 
    Value(std::string v) { sValue = v; } 

    SomeClass *cValue; 
    Value(SomeClass *v) { cValue = c; } 

}; 

std::map<std::string, Value> table; 

इसके साथ एक नकारात्मक पक्ष आपको "मूल्य" तक पहुंचने के प्रकार को जानना है। i.e .:

table["something"] = Value(5); 
SomeClass *s = table["something"].cValue; // broken pointer 

वैल्यू में जितने अधिक प्रकार डाले जाते हैं, उतना अधिक ब्लोएटेड सरणी होगी।

कोई बेहतर सुझाव?

+0

बीटीडब्ल्यू, एक std :: नक्शा एक हैश तालिका नहीं है; इसे आमतौर पर लाल-काले पेड़ के रूप में लागू किया जाता है, लेकिन किसी भी मामले में, चाबियाँ क्रम में रखी जाती हैं। Std :: tr1 :: unordered_map है, जिसे आमतौर पर हैश तालिका के रूप में कार्यान्वित किया जाता है। –

+0

क्रिस, इसे इंगित करने के लिए धन्यवाद। अब मैं इसे "सहयोगी सरणी" कह रहा हूं। –

+0

संबंधित: ["हेटरोजेनस सरणी का बिंदु क्या है?"] (Http://stackoverflow.com/questions/4534612/what-is-the-point-of-heterogenous-arrays) –

उत्तर

2

सबक्लास ValueIntValue, StringValue, और इसी तरह के साथ।

9

आपका दृष्टिकोण मूल रूप से सही दिशा में था। आप को आपके द्वारा डाले गए प्रकार को जानना होगा। आप boost::any उपयोग कर सकते हैं और आप के रूप में आप जानते हैं कि आप में डाल सिर्फ नक्शे में कुछ के बारे में डाल करने के लिए, जब तक सक्षम हो जाएगा:

std::map<std::string, boost::any> table; 
table["hello"] = 10; 
std::cout << boost::any_cast<int>(table["hello"]); // outputs 10 

कुछ उत्तर boost::variant के उपयोग इस समस्या को हल करने के लिए सिफारिश की है। लेकिन यह आपको मानचित्र में मनमाने ढंग से टाइप किए गए मानों को स्टोर नहीं करने देगा (जैसे आप चाहते थे)। आपको पहले से संभावित प्रकारों के सेट को जानना होगा। यह देखते हुए कि, आप ऊपर और अधिक आसानी से कर सकते हैं:

typedef boost::variant<int, std::string, void*> variant_type; 
std::map<std::string, variant_type> table; 
table["hello"] = 10; 
// outputs 10. we don't have to know the type last assigned to the variant 
// but the variant keeps track of it internally. 
std::cout << table["hello"]; 

ऐसा इसलिए है क्योंकि boost::variant भार के उस उद्देश्य के लिए operator<< काम करता है। यह समझने के लिए अगर आप को बचाने के लिए जो वर्तमान में संस्करण में निहित है चाहते हैं, तो आप अभी भी प्रकार पता करने के लिए है कि महत्वपूर्ण है boost::any मामले में साथ के रूप में:

typedef boost::variant<int, std::string, void*> variant_type; 
std::map<std::string, variant_type> table; 
table["hello"] = "bar"; 
std::string value = boost::get<std::string>(table["hello"]); 

एक संस्करण के लिए कार्य का क्रम एक क्रम है आपके कोड के नियंत्रण प्रवाह की संपत्ति, लेकिन किसी भी चर के उपयोग के प्रकार संकलन समय पर निर्धारित किया जाता है। तो यदि आप संस्करण से मूल्य प्राप्त करना चाहते हैं, तो आपको इसके प्रकार को जानना होगा। विज़िट दस्तावेज द्वारा उल्लिखित अनुसार, विज़िट का उपयोग करना एक विकल्प है। यह काम करता है क्योंकि संस्करण एक कोड संग्रहीत करता है जो बताता है कि किस प्रकार इसे अंतिम रूप दिया गया था। उस पर आधारित, यह रनटाइम पर का निर्णय लेता है जो विज़िटर का अधिभार उपयोग करता है। boost::variant काफी बड़ा है और पूरी तरह से मानक अनुपालन नहीं है, जबकि boost::any मानक अनुपालन है लेकिन छोटे प्रकार के लिए भी गतिशील स्मृति का उपयोग करता है (इसलिए यह धीमा है। संस्करण छोटे प्रकार के लिए ढेर का उपयोग कर सकता है)। इसलिए आपको जो भी उपयोग करना है, उससे आपको व्यापार करना होगा।

यदि आप वास्तव में वस्तुओं को उसमें रखना चाहते हैं जो केवल कुछ करने के तरीके में भिन्न होता है, तो पॉलिमॉर्फिज्म जाने का एक बेहतर तरीका है।

std::map< std::string, boost::shared_ptr<Base> > table; 
table["hello"] = boost::shared_ptr<Base>(new Apple(...)); 
table["hello"]->print(); 

कौन सा मूल रूप से इस वर्ग के लेआउट की आवश्यकता होगी:

class Base { 
public: 
    virtual ~Base() { } 
    // derived classes implement this: 
    virtual void print() = 0; 
}; 

class Apple : public Base { 
public: 
    virtual void print() { 
     // print us out. 
    } 
}; 

boost::shared_ptr एक तथाकथित स्मार्ट सूचक है आप एक आधार स्तरीय है जो आप से निकाले जाते हैं हो सकता है। यदि आप उन्हें अपने मानचित्र से निकाल देते हैं तो यह आपकी ऑब्जेक्ट्स को स्वचालित रूप से हटा देगा और कुछ और उन्हें संदर्भित नहीं कर रहा है। सिद्धांत रूप में आप एक सादे सूचक के साथ भी काम कर सकते थे, लेकिन एक स्मार्ट सूचक का उपयोग सुरक्षा को काफी बढ़ा देगा।मैंने साझा किया गया shared_ptr मैन्युअल पढ़ें।

+0

वह रनटाइम-टाइप-चेकिंग है विकल्प। संकलन-समय-प्रकार-जांच विकल्प के लिए, बूस्ट :: संस्करण भी है (एक वाटरटाइट स्थिर प्रकार-जांच समाधान के लिए विज़िटर पैटर्न के साथ उपयोग करें)। –

+0

अच्छी तरह से, हमने आईआरसी में इसके बारे में बात की है, मुझे लगता है :) बस इसे पढ़ने वाले सभी लोगों के लिए: संस्करण केवल सीमित प्रकार के स्टोर स्टोर कर सकता है, और यदि कोई प्रविष्टि से मूल्य प्राप्त करना चाहता है, तो कोई विज़िट (और इच्छा इसके प्रकार को जानने के बिना मूल्य प्राप्त करें), लेकिन कोई भी मूल्य को कहीं भी नहीं बचा सकता है। –

+0

क्योंकि विज़िटर का कौन सा संस्करण कॉल किया जाता है, वह रनटाइम पर किया जाता है। एक चर के प्रकार, हालांकि, संकलन समय पर निर्धारित किया जाता है। तो आप कुछAutoDeducedType परिणाम = boost :: apply_visitor (my_visitor(), u) नहीं कर सकते; । एक आगंतुक के सभी सेशन() को एक ही रिटर्न प्रकार मिला। –

2

क्या आप std :: map के साथ संघ का उपयोग कर सकते हैं?

बूस्ट :: संस्करण टाइपलेस चर प्रदान करता है।

असल में आप अपने सभी वैल्यू डेटा सदस्यों को निजी बना सकते हैं और एक्सेसर्स प्रदान करते हैं जो सेट नहीं होने पर त्रुटि (या फेंक) लौटाते हैं।

+0

आप std :: map के साथ एक यूनियन का उपयोग कर सकते हैं, लेकिन यूनियन केवल पीओडी-प्रकार ऑब्जेक्ट्स को पकड़ सकते हैं। – mstrobl

1

एक सीधी-आगे अनुकूलन union का उपयोग करना होगा, क्योंकि आपके पास हमेशा कुंजी के रूप में केवल एक मान होगा।

एक और पूरा समाधान इंटरफ़ेस में कुछ रन टाइम प्रकार की जानकारी को समाहित करेगा। मुख्य रूप से "यह किस प्रकार है?" और "मैं समानता के लिए मूल्यों की तुलना कैसे करूं?" फिर उस के कार्यान्वयन का उपयोग कुंजी के रूप में करें।

+0

यूनियन std :: स्ट्रिंग के – MSalters

+0

को रोक नहीं सकते हैं, वास्तव में, g ++ शिकायत "त्रुटि: सदस्य 'std :: string [...]' कन्स्ट्रक्टर के साथ संघ में अनुमति नहीं है" (अन्य चीजों के साथ)। मेरा सी ++ जंगली हो रहा है: - / –

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