2010-03-05 8 views
7

मैं एक मौजूदा ऐप को अपग्रेड करने के लिए स्मार्ट पॉइंटर्स का उपयोग करने का प्रयास कर रहा हूं, और मैं एक पहेली को दूर करने की कोशिश कर रहा हूं। मेरे ऐप में मेरे पास ऑब्जेक्ट्स का कैश है, उदाहरण के लिए उन्हें किताबें कॉल करें। अब आईडी द्वारा किताबों के इस कैश का अनुरोध किया जाता है और यदि वे कैश में हैं तो वे वापस आ जाते हैं, अगर ऑब्जेक्ट को बाहरी सिस्टम (धीमी ऑपरेशन) से अनुरोध नहीं किया जाता है और कैश में जोड़ा जाता है। एक बार कैश में ऐप में कई खिड़कियां खोली जा सकती हैं, इनमें से प्रत्येक विंडो पुस्तक का संदर्भ ले सकती है। ऐप के पिछले संस्करण में प्रोग्रामर को एड्रफ और रिलीज को बनाए रखना था, जब पुस्तक ऑब्जेक्ट का उपयोग करने वाली प्रत्येक विंडो बंद थी, अंतिम रिलीज (कैश मैनेजर पर) ऑब्जेक्ट को कैश से निकाल देगा और ऑब्जेक्ट को हटा देगा।कोई संदर्भ नहीं होने पर कैश से स्मार्ट पॉइंटर्स को कैसे निकालें?

आपने यहां श्रृंखला में कमजोर लिंक देखा होगा, यह निश्चित रूप से प्रोग्रामर को एड्रफ और रिलीज को कॉल करना याद रखता है। अब मैं स्मार्ट पॉइंटर्स (बूस्ट :: घुसपैठ) में स्थानांतरित हो गया हूं, अब मुझे एड्रफ और रिलीज को कॉल करने के बारे में चिंता करने की ज़रूरत नहीं है। हालांकि इससे किसी समस्या का कारण बनता है, कैश में ऑब्जेक्ट का संदर्भ होता है, इसलिए जब अंतिम विंडो बंद होती है, तो कैश को अधिसूचित नहीं किया जाता है कि कोई भी संदर्भ नहीं रख रहा है।

मेरा पहला विचार समय-समय पर कैश और पुर्ज ऑब्जेक्ट्स को संदर्भ संदर्भ के साथ चलाना था। मुझे यह विचार पसंद नहीं आया, क्योंकि यह एक ऑर्डर एन ऑपरेशन था और सही महसूस नहीं किया। मैं एक कॉलबैक सिस्टम के साथ आया हूं, जो बेहतर है लेकिन शानदार नहीं है। मैंने कॉलबैक सिस्टम के लिए कोड शामिल किया है, हालांकि मैं सोच रहा था कि क्या किसी को ऐसा करने का बेहतर तरीका है?

class IContainer 
{ 
public: 
    virtual void FinalReference(BaseObject *in_obj)=0; 
}; 

class BaseObject 
{ 
    unsigned int m_ref; 

public: 
    IContainer *m_container; 

    BaseObject() : m_ref(0),m_container(0) 
    { 
    } 

    void AddRef() 
    { 
     ++m_ref; 
    } 
    void Release() 
    { 
     // if we only have one reference left and we have a container 
     if(2 == m_ref && 0 != m_container) 
     { 
      m_container->FinalReference(this); 
     } 

     if(0 == (--m_ref)) 
     { 
      delete this; 
     } 
    } 
}; 

class Book : public BaseObject 
{ 
    char *m_name; 
public: 
    Book() 
    { 
     m_name = new char[30]; 
     sprintf_s(m_name,30,"%07d",rand()); 
    } 
    ~Book() 
    { 
     cout << "Deleting book : " << m_name; 
     delete [] m_name; 
    } 

    const char *Name() 
    { 
     return m_name; 
    } 
}; 

class BookList : public IContainer 
{ 
public: 
    set<BookIPtr> m_books; 

    void FinalReference(BaseObject *in_obj) 
    { 
     set<BookIPtr>::iterator it = m_books.find(BookIPtr((Book*)in_obj)); 
     if(it != m_books.end()) 
     { 
      in_obj->m_container = 0; 
      m_books.erase(it); 
     } 
    } 
}; 

namespace boost 
{ 
    inline void intrusive_ptr_add_ref(BaseObject *p) 
    { 
     // increment reference count of object *p 
     p->AddRef(); 
    } 
    inline void intrusive_ptr_release(BaseObject *p) 
    { 
     // decrement reference count, and delete object when reference count reaches 0 
     p->Release(); 
    } 
} // namespace boost 

चीयर्स रिच

+0

आपको 'बेसऑब्जेक्ट' को अनावश्यक बनाना चाहिए (घोषित करके, लेकिन एक निजी प्रतिलिपि कन्स्ट्रक्टर और असाइनमेंट ऑपरेटर परिभाषित नहीं करना चाहिए), या इसे किसी भी तरह से उचित रूप से कॉपी करने योग्य बनाना चाहिए। इसी तरह, 'बुक' में खतरनाक प्रति अर्थशास्त्र है, जो मैन्युअल रूप से प्रबंधित सरणी के बजाय 'std :: string' का उपयोग करके सबसे अच्छा तय किया जाता है। –

+0

आभासी dtor कृपया !!! – curiousguy

उत्तर

9

मैं बढ़ावा :: घुसपैठ स्मार्ट संकेत इस्तेमाल कभी नहीं किया है, लेकिन अगर आप shared_ptr स्मार्ट संकेत का प्रयोग करेंगे, तो आप अपने कैश के लिए वस्तुओं weak_ptr इस्तेमाल कर सकते हैं।

उन कमजोर_प्टर पॉइंटर्स संदर्भ के रूप में गिनती नहीं करते हैं जब सिस्टम उनकी याददाश्त को मुक्त करने का निर्णय लेता है, लेकिन जब तक ऑब्जेक्ट अभी तक नहीं हटाया जाता है तब तक एक साझा_ptr को पुनर्प्राप्त करने के लिए उपयोग किया जा सकता है।

+0

मुझे घुसपैठ पॉइंटर्स का उपयोग करना है क्योंकि कोड बेस बहुत बड़ा है और बहुत ही जुड़ा हुआ है। मैं बेस प्रकार को स्मार्ट पॉइंटर में नहीं बदल सकता। मुझे एक मौजूदा सूचक को एक स्मार्ट सूचक में बदलने और संदर्भ गणना को बनाए रखने में सक्षम होना चाहिए। कुछ घुसपैठ करने वाले पॉइंटर्स कर सकते हैं। – Rich

+0

साझा पॉइंटर्स के साथ, आपको मूल प्रकार की आवश्यकता नहीं होगी, जो आपके कोड बेस को विचलित करने के लिए एक अच्छा कदम होगा। आपको थ्रेड सुरक्षा और अपवाद सुरक्षा भी मिल जाएगी। –

+0

साझा सूचक के साथ सबसे बड़ी समस्या यह है कि मुझे साझा प्रकार के उपयोग को बढ़ावा देने की आवश्यकता होगी। मुझे मूल सी पॉइंटर का उपयोग करने में सक्षम होना चाहिए, कन्वर्ट करने के लिए बस बहुत अधिक कोड है। – Rich

4

आप boost shared_ptr का उपयोग कर सकते हैं। इसके साथ आप एक कस्टम डिलीटर प्रदान कर सकते हैं (this एसओ थ्रेड इसे कैसे करें) पर देखें। और उस कस्टम डिलीटर में आप जानते हैं कि आप अंतिम संदर्भ संख्या तक पहुंच गए हैं। अब आप कैश से पॉइंटर हटा सकते हैं।

+0

क्या आप घुसपैठ करने वाले पॉइंटर्स में कस्टम डिलीटर जोड़ सकते हैं? (मुझे पता है कि मैं घुसपैठ पॉइंटर्स के अपने संस्करण को लिखकर कर सकता हूं) – Rich

+1

जब तक पॉइंटर कैश में संग्रहीत होता है, संदर्भ गणना कभी 0 तक नहीं गिर जाएगी और कस्टम डिलीटर नहीं कहा जाएगा। – visitor

+1

@ विज़िटर: हाँ आप सही हैं, लेकिन ओपी कैश तंत्र को फिर से डिज़ाइन कर सकता है। कैश में कच्चे पॉइंटर्स होते हैं जिन्हें जीयूआई विंडोज़ द्वारा एक्सेस किए जाने से पहले 'shared_ptr' द्वारा लपेटा जाएगा। जब सभी पॉइंटर्स गुंजाइश से बाहर जाते हैं, तो उपयोगकर्ता कैश एंट्री को हटा सकता है और यदि आवश्यक हो तो उसे भी हटा सकता है। – Abhay

1

आपको shared_ptr के बजाय अपने कैश weak pointers में रखने की आवश्यकता है।

+0

कृपया ध्यान दें कि 'weak_ptr' बिल्कुल "पॉइंटर" नहीं है। इसमें "पॉइंटर" अर्थपूर्ण नहीं है, लेकिन "कमजोर संदर्भ" अर्थपूर्ण है। – curiousguy

0

आप अपने कैश क्लास के लिए intrusive_weak_ptr लिखने पर विचार कर सकते हैं। आपको समय-समय पर अपने कैश में समाप्त होने वाले कमजोर पॉइंटर्स को साफ़ करने के लिए कुछ करने की आवश्यकता होगी, लेकिन यह वास्तविक कैश किए गए ऑब्जेक्ट्स को साफ करने के रूप में महत्वपूर्ण नहीं है।

http://lists.boost.org/boost-users/2008/08/39563.php एक कार्यान्वयन है जो बूस्ट मेलिंग सूची में पोस्ट किया गया था। यह धागा सुरक्षित नहीं है, लेकिन यह आपके लिए काम कर सकता है।

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