2010-07-31 10 views
5

मैं, कुछ अन्य उदाहरण के लिए कुछ structs मैप करने के लिए कोशिश कर रहा हूँ इस तरह:भंडारण struct उदाहरणों :: नक्शा

template <typename T> 
class Component { 
public: 

    typedef std::map<EntityID, T> instances_map; 

    instances_map instances; 

    Component() {}; 

    T add(EntityID id) { 
     T* t = new T(); 
     instances[id] = *t; 
     return *t; 
    }; 
}; 
तब मैं इसका उपयोग इस प्रकार

:

struct UnitInfos { 
    int owner_id; 
    int health; 
    float x, y; 
}; 

class LogicComponent : public Component<UnitInfos> {}; 

comp.instance[id]; 

मैं मूलभूत मूल्यों पर प्रारंभ गुणों के साथ एक breand नई वस्तु मिलती है: समस्या यह है कि जब यह बाद में डेटा पर बाद में, इस तरह पुनः प्राप्त है।

क्या कोड के इस टुकड़े के साथ कुछ स्वाभाविक रूप से गलत है, या क्या मैं समस्या के बारे में जानकारी छोड़ रहा हूं?


@aaa सुझाव के अनुसार, मैं

typedef std::map<EntityID, T> instances_map; 
instances_map instances; 
T& add(EntityID id) { 
    instances[id] = T(); 
    return instances[id]; 
}; 

लिए कोड बदलने लेकिन जब मैं का उपयोग यह

UnitInfos &info = logic_c.instances[id]; 

info.x का मूल्य अभी भी 0. किसी भी संकेत दिए गए है?


समस्या यह थी कि मैंने किसी अन्य वर्ग में LogicComponent के संदर्भ को कैसे संग्रहीत किया। LogicComponent& logic_c; के बजाय LogicComponent logic_c; का उपयोग करना। यह अब काम करता है, लेकिन मैं मानचित्र में पॉइंटर्स संग्रहीत कर रहा हूं (@ aaa के सुझाव के बजाय)। क्या यह एक बुरा विचार है?

+1

वहाँ कुछ कोड के इस टुकड़े के साथ स्वाभाविक गलत _is_: गतिशील रूप से 'T' निर्माण नहीं करतीं। ऐसा करने का कोई कारण नहीं है, और जैसा कि अब लिखा गया है, आप उस वस्तु को रिसाव करते हैं। जिस समस्या के लिए आप देख रहे हैं, आपको 'EntityID' के लिए ऑपरेटर कार्यान्वयन से कम पोस्ट करना होगा और आप मानचित्र पर' ऑपरेटर [] 'को कैसे कॉल कर रहे हैं (यानी, आप जिस आईडी को पास करते हैं उसे कैसे बनाते हैं' ऑपरेटर [] '?)। –

+0

EntityID को अभी टाइप किया गया है 'टाइपपीफ हस्ताक्षरित लंबी EntityID;'। – sharvey

उत्तर

3

उन तर्कों को स्पष्ट करें जिन्हें आप LogicComponent पर करना चाहते हैं। मान लें कि आप कुछ इस तरह प्राप्त करने के लिए कोशिश कर रहे हैं:

चरण 1:

LogicComponent comp; 
EntityID id = 99; 
UnitInfos info = comp.add(id); 

चरण 2:: मानचित्र में नया प्रविष्टि जोड़ें

info.x = 10.0; 
info.y = 11.0 
// etc 

चरण 3:: जानकारी प्रारंभ हो जाओ फिर से जानकारी वस्तु:

UnitInfos info2 = comp.instances[id]; // this is uninitialized. 

फिर, कुछ कोड टिप्पणी क्रम में हैं:

comp.add द्वारा लौटाई गई जानकारी ऑब्जेक्ट उस मानचित्र की एक कॉपी है जिसे आपने मानचित्र में जोड़ा था। इसे संशोधित करके, आप मानचित्र में क्या संशोधित नहीं कर रहे हैं।

सबसे आसान फिक्स ऑब्जेक्ट के बजाय ऑब्जेक्ट पर पॉइंटर्स का नक्शा बनाना है।

typedef std::map<EntityID, T*> pinstances_map; 

T * add(EntityID id) { 
    T* t = new T(); 
    instances[id] = t; 
    return t; 
}; 

// initialize as 
UnitInfo *info = comp.add(id); 
info->x = 10.0; 
info->y = 11.0; 

// retrieve as 
UnitInfos *info = comp.instances[id]; 

इसके अलावा, मैप ऑब्जेक्ट को सार्वजनिक रूप से उजागर करने के बजाय मैप किए गए मान को प्राप्त करने के लिए एक्सेसर विधि का उपयोग करें। उदाहरण परिवर्तनीय संरक्षित करें, और एक सार्वजनिक get() विधि जोड़ें।

संपादित करें: इस कोड मेरे लिए ठीक काम करता है:

#include <map> 
#include <iostream> 
using namespace std; 

template<typename T> 
class Component 
{ 
public: 
     typedef map<long, T*> pinstances_map; 
     pinstances_map instances; 

     T * add(long id) 
     { 
       T *t = new T(); 
       instances[id] = t; 
       return t; 
     } 
}; 

struct UnitInfo 
{ 
     float x, y; 
}; 

class LogicComponent: public Component<UnitInfo> {}; 

int main() 
{ 
     LogicComponent comp; 
     UnitInfo *info = comp.add(99); 
     info->x = 10.0; 
     info->y = 11.0; 

     UnitInfo *info2 = comp.instances[99]; 
     cout << info2->x << " " << info2->y; 

     return 0; 
} 
+0

जो आपने वर्णन किया है वह वही है जो मैं प्राप्त करने की कोशिश कर रहा हूं। आपके द्वारा वर्णित किए गए कार्यों पर स्विच करना मैंने कोशिश की है, लेकिन मैंने आपकी अंतिम पंक्ति के बाद जानकारी-> x को कॉल करते समय, मुझे EXX_BAD_ACCESS मिलता है, जिसमें 0x0 की ओर इशारा करते हुए जानकारी होती है। – sharvey

+0

मैं सहमत हूं, यह कोड काम करता है।जब मैं कोड के किसी अन्य भाग से इसे एक्सेस करने का प्रयास करता हूं (रेंडर फ़ंक्शन 'glutDisplayFunc' और' glutIdleFunct' को पास करता है, तो पॉइंटर्स अभी भी 0x0 पर इंगित करते हैं। – sharvey

+0

क्या आप एक ही LogicComp ऑब्जेक्ट तक पहुंच रहे हैं? – carlsborg

4

हो सकता है कि

T add(EntityID id) { 
    T* t = new T(); 
    instances[id] = *t; 
    return *t; // return value and map instance are not the same anymore 
}; 

की तरह आप के रूप में अपने अनुक्रमण ऑपरेटर परिभाषित

T& add(EntityID id) { 
    instances[id] = T(); 
    return instances[id]; 
}; 
+0

मैंने कोड बदलने की कोशिश की, लेकिन यह अभी भी मुझे एक ही समस्या देता है। क्या मुझे इस तरह के उदाहरण को पुनर्प्राप्त करना चाहिए: 'UnitInfos info = logic_c.instances [id];'? – sharvey

+0

@ शार्वे संख्या, 'यूनिट इन्फोस जानकारी' एक नया उदाहरण है, 'यूनिट इन्फोस और जानकारी' मौजूदा उदाहरण का संदर्भ है। यदि आप जावा से आते हैं, तो आपको इसे पढ़ने की आवश्यकता हो सकती है: http://www.parashift.com/c++-faq-lite/references.html – Anycorn

+0

मैं जावा-आश पृष्ठभूमि से आया हूं। अजीब चीज यह है कि जब मैं इसे बदलने के बाद इसे एक्सेस करता हूं, तो मूल्य सही होता है; लेकिन जब मैं इसे बाद में प्राप्त करता हूं, एक्स का मान अभी भी 0 है। मैं प्रश्न को अद्यतन करता हूं। धन्यवाद। – sharvey

2

ऐसा लगता है होना चाहिए:

template <typename T> 
T& Component::operator[](EntityID id) 
{ 
    return instances[id]; 
} 

या ऐसा ही कुछ।

इस की संभावना अप्रत्याशित प्रभाव है कि यह स्वचालित रूप से नक्शे में T के डिफ़ॉल्ट-निर्माण उदाहरण से जोड़ दिया जाएगा और फिर इसे लौट गैर exising प्रविष्टियों के लिए है। यह std::map में किया जाता है इसलिए प्राकृतिक असाइनमेंट सिंटैक्स instances[10] = t; काम करता है।

यहां मुख्य बिंदु स्थिरता है। मूल्य द्वारा और एक const विशेषता के साथ लौटने को छोड़कर बिल्कुल के रूप में ऊपर यह निर्धारित करें:

template <typename T> 
T Component::operator[](EntityID id) const 
{ 
    return instances[id]; 
} 

इस तरह से जब आप गैर मौजूदा कुंजी द्वारा पुन: प्राप्त करने की कोशिश आप एक अपवाद मिल जाएगा।अभी तक बेहतर, बस typedef यह bellow की तरह है और इसके साथ किया जाना:

typedef std::map<EntityID,UnitInfos> EntityUnitMap; 

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

+0

धन्यवाद, अब मैं समझता हूं कि क्यों C++ faq-lite का कहना है कि आपको शायद C++ में अधिकांश समय पॉइंटर की आवश्यकता नहीं है। ऐसा नहीं लगता था कि यह इस तरह कुछ पर भी लागू होगा। मैं उदाहरण उप-क्षेत्र के माध्यम से उदाहरण का उपयोग कर रहा हूं, इसलिए मैं [] ऑपरेटर को घटक टेम्पलेट पर नहीं बुलाता हूं। बेशक मेरे द्वारा गलती हो सकती है। मैं ऑपरेटर को पूरी तरह कार्यान्वित करता हूं [] जैसा आपने सुझाव दिया है, क्योंकि यह बहुत अच्छा है। धन्यवाद। – sharvey

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