2011-12-09 15 views
14

मेरी noob प्रतिष्ठा की वजह से, मैं, इस Thread का उत्तर दे सकते नहीं विशिष्ट स्वीकार किए जाते हैं जवाब में:कोई संदर्भ नहीं होने पर कैश से (गैर-घुसपैठ) स्मार्ट पॉइंटर्स को कैसे हटाया जाए?

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

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

यह निश्चित रूप से एक सहज विचार है, हालांकि, सी ++ मानक कमजोर_प्टर्स की तुलना का समर्थन नहीं करता है, इसलिए इसे सहयोगी कंटेनरों के लिए कुंजी के रूप में उपयोग नहीं किया जा सकता है। यह weak_ptrs के लिए एक तुलना ऑपरेटर को लागू करने से उन्हें धोखा दिया जा सकता है:

template<class Ty1, class Ty2> 
    bool operator<(
     const weak_ptr<Ty1>& _Left, 
     const weak_ptr<Ty2>& _Right 
    ); 

इस समाधान के साथ समस्या यह है कि

(1) तुलना ऑपरेटर (हर तुलना के लिए स्वामित्व प्राप्त करने के लिए है यानी weak_ptr से बनाने shared_ptrs रेफरी)

(2) कमजोर_प्टर कैश से मिटा नहीं जाता है जब संसाधन का प्रबंधन करने वाले अंतिम साझा_प्टर को नष्ट कर दिया जाता है, लेकिन कैश में एक समाप्त हो गया कमजोर_प्टर रखा जाता है।

के लिए (2), हम एक कस्टम विनाशक (DeleteThread) प्रदान कर सकते हैं, हालांकि, इसे हटाने के लिए टी * से कमजोर_प्टर बनाने की आवश्यकता होगी, जिसे कैश से कमजोर_प्टर को मिटाने के लिए उपयोग किया जा सकता है ।

मेरा प्रश्न यह होगा कि स्मार्ट पॉइंटर्स का उपयोग करके कैश के लिए कोई बेहतर तरीका है (मैं वीसी 100 कंपाइलर का उपयोग कर रहा हूं, कोई बढ़ावा नहीं देता), या क्या मुझे बस यह नहीं मिलता है?

चीयर्स, डैनियल

+1

आप नहीं कर सकते हैं किसी भी कुंजी-आधारित कंटेनर की कुंजी बदलें !!! यह अपरिवर्तनीय होना चाहिए! आपके पास कुछ कस्टम डिलीट-द-आखिरी हो सकता है जो आपके कंटेनर से प्रविष्टि तक पहुंचता है और हटा देता है। लेकिन कंटेनर में एक महत्वपूर्ण परिवर्तन मूल्य होने पर एक बड़ा नंबर नहीं है। – Mordachai

+0

यह बिल्कुल समस्या है, मुझे एक कस्टम डिलीटर प्रदान करना होगा जो कैश में ऑब्जेक्ट को मिटा देता है ताकि कैश में समाप्त होने वाले पॉइंटर से बच सकें। या आप आम तौर पर बात कर रहे हैं, क्योंकि रेफ-गिनती बदल रही है? – dwn

उत्तर

2

बात है पहुँचता है, आपके Cache वस्तु कैश्ड ने संबोधित नहीं किया गया है खुद, अन्यथा यह बेकार के बारे में होगा।

Cache का विचार कुछ गणना से बचने के लिए है, इसलिए सूचकांक गणना के पैरामीटर होंगे, जो पहले से मौजूद होने पर सीधे परिणाम के लिए मानचित्रित होंगे।

अब, आपको वास्तव में कैश से ऑब्जेक्ट्स को निकालने के लिए दूसरी अनुक्रमणिका की आवश्यकता हो सकती है, लेकिन यह अनिवार्य नहीं है। निश्चित रूप से अन्य रणनीतियों उपलब्ध हैं।

यदि आप वास्तव में कैश से ऑब्जेक्ट्स को हटाना चाहते हैं जैसे ही उन्हें एप्लिकेशन में कहीं और उपयोग नहीं किया जाता है, तो प्रभावी रूप से, आप द्वितीयक अनुक्रमणिका का उपयोग कर सकते हैं। हालांकि यहां विचार T* के अनुसार सूचकांक होगा, weak_ptr<T> नहीं, लेकिन weak_ptr<T> को आस-पास रखने के लिए, अन्यथा आप एक ही संदर्भ गणना पर एक नया shared_ptr नहीं बना सकते हैं।

सटीक संरचना पर कि क्या गणना के मापदंडों, इस तथ्य के बाद recompute करने अगर वे कर रहे हैं मुश्किल है निर्भर करता है, एक सरल उपाय है:

template <typename K, typename V> 
class Cache: boost::enable_shared_from_this<Cache> 
{ 
    typedef std::map<K, boost::weak_ptr<V>> KeyValueMap; 
    typedef std::map<V*, KeyValueMap::iterator> DeleterMap; 

    struct Deleter { 
    Deleter(boost::weak_ptr<Cache> c): _cache(c) {} 

    void operator()(V* v) { 
     boost::shared_ptr<Cache> cache = _cache.lock(); 
     if (cache.get() == 0) { delete v; return; } 

     DeleterMap::iterator it = _cache.delmap.find(v); 
     _cache.key2val.erase(it->second); 
     _delmap.erase(it); 
     delete v; 
    } 

    boost::weak_ptr<Cache> _cache; 
    }; // Deleter 

public: 
    size_t size() const { return _key2val.size(); } 

    boost::shared_ptr<V> get(K const& k) const { 
    KeyValueMap::const_iterator it = _key2val.find(k); 
    if (it != _key2val.end()) { return boost::shared_ptr<V>(it->second); } 

    // need to create it 
    boost::shared_ptr<V> ptr(new_value(k), 
     Deleter(boost::shared_from_this())); 

    KeyValueMap::iterator kv = _key2val.insert(std::make_pair(k, ptr)).first; 
    _delmap.insert(std::make_pair(ptr.get(), kv)); 

    return ptr; 
    } 


private: 
    mutable KeyValueMap _key2val; 
    mutable DeleterMap _delmap; 
}; 

नोट विशेष मुश्किल: सूचक Cache से अधिक जीवित हो सकता है , इसलिए हम कुछ चाल यहाँ ... जरूरत

और आपकी जानकारी के लिए, जबकि यह संभव लगता है, मैं इस कोड में बिल्कुल आश्वस्त नहीं हूं: अपरीक्षित, अप्रमाणित, bla, bla;)

+0

समाधान अच्छा है, विशिष्ट में 'DeleterMap' जो मैं खोज रहा था। लेकिन मैं इस बिंदु पर असहमत हूं कि कैश किए गए ऑब्जेक्ट कैश की कुंजी नहीं है: विचार यह है कि पॉइंटर्स का कैश होना चाहिए जो सुनिश्चित करता है कि कोई 2 पॉइंटर्स नहीं हैं जो खराब होने पर बराबर होते हैं (सॉर्टिंग के लिए कम तुलनात्मक संदर्भ का उपयोग करें)। यह मुझे सुरक्षित वस्तुओं के लिए कई ऑब्जेक्ट्स में ऑब्जेक्ट पॉइंटर्स (अपरिवर्तनीय) ऑब्जेक्ट पॉइंटर्स का पुन: उपयोग करने की अनुमति देता है। फिर भी, मैं बस अपने अधिक सामान्य दृष्टिकोण 'typedef std :: मानचित्र का उपयोग कर सकते हैं <कश्मीर, को बढ़ावा देने :: weak_ptr > KeyValueMap;' और एक 'std :: set' साथ बदलें। – dwn

+0

मैंने अभी तक इसका परीक्षण नहीं किया है, लेकिन लाइन 'if (cache.get() == 0) {हटाएं v; } 'होना चाहिए' अगर (_cache.get() == 0) {हटाएं v; वापसी; } ' – dwn

+0

@dawn: अपनी विशेष स्थिति के बारे में: वास्तव में, अपनी जरूरतों के लिए अनुकूल :) अपने टिप्पणी के बारे में ... doh! धन्यवाद, मैंने इसे ठीक किया :) –

4

आप क्या हासिल करना चाहते के लिए एक संभावित समाधान हो सकता है

चलें कहना T अपने वस्तु है और shared_ptr<T> अपने साझा किया जाता है ptr

  1. केवल में नियमित रूप से T* है आपके कैश।
  2. के लिए अपने shared_ptr<T>
  3. अपने कस्टम Deleter हटाने पर कैश से अपने T* मिटा है एक कस्टम Deleter है।

इस तरह कैश अपने shared_ptr<T> के रेफरी संख्या में वृद्धि नहीं करता, लेकिन अधिसूचित किया गया है जब रेफरी गिनती 0.

struct Obj{}; 

struct Deleter 
{ 
    std::set<Obj*>& mSet; 
    Deleter(std::set<Obj*>& setIn ) 
     : mSet(setIn) {} 

    void operator()(Obj* pToDelete) 
    { 
     mSet.erase(pToDelete); 
     delete pToDelete; 
    } 
}; 

int main() 
{ 

    std::set< Obj* > mySet; 
    Deleter d(mySet); 
    std::shared_ptr<Obj> obj1 = std::shared_ptr<Obj>(new Obj() , d); 
    mySet.insert(obj1.get()); 
    std::shared_ptr<Obj> obj2 = std::shared_ptr<Obj>(new Obj() , d); 
    mySet.insert(obj2.get()); 

    //Here set should have two elements 
    obj1 = 0; 
    //Here set will only have one element 

    return 42; 
} 
+0

धन्यवाद पैरापुरा, समाधान अच्छा है और मैं क्या चाहता था। मुझे लगता है कि आपकी एक छोटी गलती है: 'std :: set mSet; 'एक संदर्भ होना चाहिए। – dwn

+0

@ धन्यवाद .... मेरी जल्दी में मैंने अभी तक पूरी तरह से इसका परीक्षण नहीं किया ... मेरी गलती को संपादित और सही किया। मुझे ** डिलीटर फ़ैक्टर ** हस्ताक्षर के बारे में निश्चित नहीं है। वीएस 2011 –

+0

@ डॉन के तहत काम करने लगता है अगर आप इसे अपनी समस्या हल करते हैं तो क्या आप इसे उत्तर के रूप में स्वीकार कर सकते हैं? –

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

  • कोई संबंधित समस्या नहीं^_^