2013-07-31 9 views
6

मैं अपने डिजाइन में पॉइंटर-टू-पॉइंटर का उपयोग करने के लिए अपने खेल के कुछ स्थानों पर खुद को ढूंढता हूं। उदाहरण के लिए, मेरे पास कक्षा OpenGLRenderer है जो मेटेस दिए गए वर्टेक्स/इंडिस/टेक्सकोर्ड डेटा, सामग्री प्रोप इत्यादि सामग्री और फिर एक वर्ग ResourceManifest बनाता है जो फाइल से मेष/सामग्री को कैश करता है और इन संसाधनों में से किसी एक को लोड करने पर इसका एक उदाहरण बनाता है OpenGLRenderer का उपयोग कर। तो वहां एक युग्मन है।सी ++ में पॉइंटर-टू-पॉइंटर्स के विकल्प?

मैं आम तौर पर जब कोडिंग जो निम्नलिखित रिश्ते के लिए मुझे लुभाता है आरए II डिजाइन को रोजगार चाहते:

ResourceManifest(OpenGLRenderer** renderer); 

क्योंकि जब ओपन संदर्भ में तोड़ दिया गया और सभी ओपन राज्य विशेष के सामान इसे पुनः शुरू करना है, इस तरह के की जरूरत है जब खिड़की को पुनर्जीवित करते हैं, तो मैं सिर्फ OpenGLRenderer को फिर से बना देता हूं और कन्स्ट्रक्टर/विनाशक को सभी काम करता है और ResourceManifest इसका उपयोग कभी भी बुद्धिमान नहीं होगा।

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

+0

आपके पास स्मार्ट पॉइंटर के लिए एक स्मार्ट पॉइंटर हो सकता है। –

+0

यह एक भयानक हैक हो सकता है, इसलिए मैं केवल एक टिप्पणी के रूप में पोस्ट कर रहा हूं; क्या आप OpenGLRenderer को प्लेसमेंट नए और एक स्पष्ट डॉटोर कॉल के साथ पुन: आवंटित कर सकते हैं, जिससे स्मृति पता लगातार स्थिर रहेगा? (अस्वीकरण: मैं कुल ग्राफिक्स-नोब हूं) – bitmask

+3

एआरएम, एक संदर्भ-से-पॉइंटर बहुत स्पष्ट उत्तर है? वैकल्पिक रूप से, एक रैपर प्रकार का उपयोग करें और उस रैपर के उदाहरण के लिए एक संदर्भ या सूचक संग्रहीत करें, और रैपर के 'OpenGLRenderer * 'सदस्य को एक अलग रेंडरर –

उत्तर

3

जैसा कि पहले से ही कहा गया है, आप एक स्मार्ट सूचक का संदर्भ दे सकते हैं।

हालांकि, यदि आप स्मार्ट पॉइंटरनेस से परे कार्यक्षमता प्रदान करना चाहते हैं तो आप अपना कोड एक पुनरावर्तक में बना सकते हैं, खासकर यदि अंतर्निहित डेटा संरचनाएं समान नहीं हैं। दोबारा, यह एक बात है कि आप पॉइंटर को अपने पॉइंटर का उपयोग कैसे करेंगे। फिर जो भी इंटरफ़ेस आप अंततः उपयोग करते हैं वह स्वयं को एक स्मार्ट सूचक में लपेटा जा सकता है।

+0

एक स्मार्ट सूचक के संदर्भ में हो सकता है? –

+1

यह कोई जवाब नहीं है: -/टिप्पणी करने में असमर्थता का मतलब यह नहीं है कि आप इसके बजाय उत्तरों का उपयोग कर सकते हैं। –

+3

@ निकोससी। उसे कम से कम संपादित करने का मौका दें। –

1

मुझे क्या आश्चर्य है कि अगर यह सादे पुराने पॉइंटर-टू-पॉइंटर्स का उपयोग करने के पर्याप्त औचित्य है, तो क्या कोई और आधुनिक उपकरण या तकनीक उपलब्ध है?

  1. एक वर्ग ResourceLoader कहा जाता है जो std::map<ResourceId, std::weak_ptr<OpenGLResource> > जहां ओपन संसाधन सामान्य ओपन संसाधनों द्वारा प्रयोग किया जाता clas है शामिल नहीं है: मैं

अपने विशेष परिदृश्य में, आपको ऐसा ही कुछ इस्तेमाल कर सकते हैं। RESOURCEID जो भी आप विशिष्ट संसाधन की पहचान करने के लिए उपयोग है (फ़ाइल नाम जो कुछ भी)

  • जब आप नए संसाधन ResourceLoader चेकों weak_ptr के लिए नक्शे के shared_ptr करने के लिए उन्हें धर्मान्तरित और उन्हें रिटर्न लोड। यदि मानचित्र में weak_ptr एस नहीं हैं, या यदि वे शून्य हैं, तो वह नया shared_ptr बनाता है, इसे weak_ptr मानचित्र में धक्का देता है, और इसे वापस करता है।

    अर्द्ध C++ peudocode (अनियंत्रित, सबसे अधिक संभावना गलत वर्तनी और वाक्य रचना त्रुटियाँ हैं):

    typedef std::shared_ptr<Resource> ResourcePtr; 
        typedef std::weak_ptr<Resource> ResourceWeakPtr; 
        typedef std::map<ResourceId, ResourceWeakPtr> ResourceMap; 
    
        class Loader{ 
        public: 
         ....    
         ResourcePtr loadResource(ResourceId id){ 
          ResourceMap::iterator found = resoruceMap.find(id); 
          ResourcePtr result; 
          if ((found == resourceMap.end()) || !(result = found->second.lock())){ 
            result = createResource(id); 
            resourceMap.insert(std::make_pair(id, ResourceWeakPtr(result))); 
          } 
          return result;      
         } 
         void reloadAllResources(){ 
          for (ResourceMap::iterator i = resourceMap.begin(); i != resourceMap.end(); i++){ 
            ResourcePtr cur = i->second.lock(); 
            if (cur) 
             cur->reload(); 
          } 
         } 
        protected: 
         ResourceMap resourceMap; 
         ResourcePtr createResource(ResourceId id){ 
          return ResourcePtr(new Resource()); 
         } 
        }; 
    
  • आप खो संसाधनों realod करना चाहते हैं, तो आप बस ResourceMap के माध्यम से पुनरावृति, और हर वस्तु है कि 'hasn पर फिर से लोड फोन टी समाप्त हो गया। reloadAllResources
  • 0

    देखें मैं भी यकीन है कि मैं पूरी तरह से अपने प्रश्न समझते हैं, लेकिन मुझे इसे एक शॉट देना नहीं कर रहा हूँ: आप std::weak_ptr इस्तेमाल कर सकते हैं?g++ example.cpp -std=c++11 (जीसीसी 4.7.2):

    #include<memory> 
    #include<iostream> 
    
    class Renderer { 
    public: 
        Renderer() 
         : m_calls(0) { } 
        void render() { 
        m_calls++; 
        std::cout<<"Issued render call #"<<m_calls<<std::endl; 
        } 
        void reset() { 
        std::cout<<"Reset called"<<std::endl; 
        m_calls = 0; 
        } 
    private: 
        size_t m_calls; 
    }; 
    
    class Context { 
    public: 
        Context(std::shared_ptr<Renderer> prenderer) 
         : m_prenderer(prenderer) { 
        } 
        void build_cache() { 
        if(auto renderer = m_prenderer.lock()) { 
         renderer->render(); 
        } else { 
         std::cout<<"Handle the case when I don't have a renderer to work with"<<std::endl; 
        } 
        } 
    private: 
        std::weak_ptr<Renderer> m_prenderer; 
    }; 
    
    
    int main() { 
        auto renderer = std::make_shared<Renderer>(); 
        Context ctx(renderer); 
        ctx.build_cache(); 
        ctx.build_cache(); 
        std::cout<<"Here I reset the renderer"<<std::endl; 
        renderer->reset(); 
        ctx.build_cache(); 
    
    } 
    

    के रूप में संकलित:

    निम्नलिखित (काल्पनिक) उदाहरण पर विचार करें। आउटपुट:

    Issued render call #1 
    Issued render call #2 
    Here I reset the renderer 
    Reset called 
    Issued render call #1 
    

    std::weak_ptr के प्रयोजन के स्वामित्व साझा किए बिना एक सूचक साझा करने के लिए है। तो आप अपने Renderer को रीसेट या पूरी तरह से फिर से बना सकते हैं, और यह Context के लिए असीमित होगा। इसके अलावा, एक शून्य सूचक के लिए dereferencing अच्छी तरह से परिभाषित व्यवहार है।

    +0

    मुझे नहीं लगता कि यह समस्या हल करता है। यदि कोई नया 'रेंडरर' बनाया गया है तो आप 'संदर्भ :: m_prenderer' को कैसे अपडेट करते हैं? –

    +0

    @ जोनाथन वाकई आप सही हैं - मेरे पास इस प्रश्न का उत्तर नहीं है (मैंने साझा पॉइंटर को रीसेट करने का प्रयास किया है, और उम्मीद है कि कमजोर पॉइंटर नए साझा पॉइंटर को अस्वीकार कर देगा, यह स्पष्ट रूप से काम नहीं करता है)। दूसरे शब्दों में ... इसे ट्वीव करके, मैं "पॉइंटर टू पॉइंटर" के मामले में अभिसरण कर रहा हूं, जो मुझे मूल स्थिति में छोड़ देता है। ओह अच्छा! – Escualo

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