2010-04-17 11 views
9

इस insightful article में, क्यूटी प्रोग्रामर में से एक विभिन्न प्रकार के स्मार्ट पॉइंटर्स क्यूटी लागू करने की कोशिश करता है। शुरुआत में, वह डेटा साझा करने के बीच एक अंतर बना देता है और संकेत खुद को साझा करने:सी ++ स्मार्ट पॉइंटर्स: शेयरिंग पॉइंटर्स बनाम डेटा साझा करना

सबसे पहले, एक बात सीधे मिलता है: वहाँ संकेत दिए गए और साझा करने के डेटा को साझा करने के बीच एक अंतर है। जब आप शेयर पॉइंटर्स, पॉइंटर का मूल्य और उसके जीवनकाल को स्मार्ट पॉइंटर क्लास द्वारा संरक्षित किया जाता है। अन्य शब्दों में, पॉइंटर invariant है। हालांकि, ऑब्जेक्ट कि पॉइंटर यह इंगित करता है कि इसके नियंत्रण से बाहर है। हम नहीं जानते कि ऑब्जेक्ट कॉम्पैक्टिव है या नहीं, यदि यह असाइन करने योग्य है या नहीं।

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

सचमुच, मैं बस इस स्पष्टीकरण को कम नहीं करता हूं। लेख टिप्पणियों में एक स्पष्टीकरण याचिका थी, लेकिन मुझे लेखक की व्याख्या पर्याप्त नहीं मिली।

यदि आप समझते हैं, तो कृपया समझाएं। यह भेद क्या है, और अन्य साझा सूचक वर्ग (यानी बढ़ावा से या नए सी ++ मानकों) इस वर्गीकरण में कैसे फिट होते हैं?

अग्रिम धन्यवाद

+0

यह क्यूटी चीज अभी भी मुझे भ्रमित कर रही है :) –

उत्तर

1

पहले मामले में, आप सूचक को अविवेक का एक स्तर जोड़ने के लिए, ऐसा है कि उद्देश्य यह है कि स्मार्ट सूचक का प्रतिनिधित्व करती है मूल सूचक गिर्द घूमती है। ऑब्जेक्ट में केवल एक पॉइंटर है और मूल पॉइंटर के संदर्भों को ट्रैक रखने के लिए यह रैपर का काम है।

template<typename T> 
struct smart_ptr { 
    T *ptr_to_object; 
    int *ptr_to_ref_count; 
}; 

आप struct कॉपी करते हैं, अपनी कॉपी/आवंटित कोड सुनिश्चित करने के लिए कि संदर्भ गिनती वृद्धि की जाती है (या कम कर अगर वस्तु को नष्ट कर दिया जाता है) होगा लेकिन: कोड का एक बहुत ही साधारण सा ऐसा दिखाई दे सकता वास्तविक लपेटा हुआ वस्तु का सूचक कभी नहीं बदलेगा और केवल उथले नकल की जा सकती है। चूंकि संरचना बहुत छोटी है, कॉपी करने के लिए यह आसान और सस्ता है और संदर्भ गणना में हेरफेर करने के लिए आपको "सब" करना है।

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

कम से कम है कि क्या भेद मेरे लिए की तरह लगता है, लेकिन मैं अब तक पहचान है कि मैं अपने रास्ते वापस खोजने के लिए गूगल मैप्स आवश्यकता होगी बंद हो सकता है।

7

एक बाद की टिप्पणी में उन्होंने इस मामले में थोड़ा

इस महत्वपूर्ण बिंदु मैं पहले खंड में के माध्यम से प्राप्त करने की कोशिश की है ऊपर साफ करता है। जब आप QSharedPointer का उपयोग करते हैं, तो आप सूचक का स्वामित्व साझा कर रहे हैं। वर्ग केवल पॉइंटर को नियंत्रित करता है और संभालता है - कुछ और (डेटा तक पहुंच की तरह) इसके दायरे से बाहर है। जब आप QSharedDataPointer का उपयोग करते हैं, तो आप डेटा साझा कर रहे हैं। और वह वर्ग निहित साझाकरण के लिए है: इसलिए यह विभाजित हो सकता है।

कि व्याख्या करने के लिए कोशिश कर रहा है:

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

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

डेटा साझा करना का मतलब है स्मार्ट सूचक पर्याप्त पर्याप्त के डेटा है कि यह पता बदल सकते हैं की ओर इशारा किया की ओर इशारा किया जानता है (और यह, आदि डेटा पर कॉपी करने की जरूरत है)। तो, पॉइंटर्स अब विभिन्न पते पर इंगित कर सकते हैं। चूंकि पता अलग है, पता अब साझा नहीं किया गया है। यह वही है std::string कुछ कार्यान्वयन पर करता है, भी है:

std::string a("foo"), b(a); 
// a and b may point to the same storage by now. 
std::cout << (void*)a.c_str(), (void*)b.c_str(); 
// but now, since you could modify data, they will 
// be different 
std::cout << (void*)&a[0], (void*)&b[0]; 

डेटा साझा करना जरूरी नहीं क्या आप के लिए प्रस्तुत एक सूचक है। आप और cout << a; के शुद्ध माध्यमों द्वारा std::string का उपयोग कर सकते हैं और c_str() फ़ंक्शंस को कभी भी स्पर्श नहीं कर सकते हैं। अभी भी साझा करना दृश्य के पीछे हो सकता है। एक ही बात कई क्यूटी वर्गों और अन्य विजेट टूलकिट्स के वर्गों के साथ होती है, जिसे कहा जाता है (या लिखने पर प्रतिलिपि) पर प्रतिलिपि बनाएँ। तो मुझे लगता है कि एक इस तरह यह योग हो सकता है:

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

तो वर्गीकृत करने के लिए

  • boost::shared_ptr, boost::intrusive_ptr कोशिश कर रहा।
  • QString, QPen, QSharedDataPointer: उसमें शामिल डेटा साझा करें।
  • std::unique_ptr, std::auto_ptr (और QScopedPointer): पॉइंटर और न ही डेटा साझा करें। इस बिंदु पर

    BigArray a; 
    a[0]=1;//initializaation etc 
    BigArray b=a; 
    

    हम इस अपरिवर्तनीय

    assert(a[0]==b[0]); 
    

    डिफ़ॉल्ट कॉपी चाहते हैं:

3

struct BigArray{ 
    int operator[](size_t i)const{return m_data[i];} 
    int& operator[](size_t i){return m_data[i];} 
private: 
    int m_data[10000000]; 
}; 

और अब कहते हैं कि हम दो उदाहरणों था हम इस वर्ग था कहो ctor तथापि गहरी नकल ई की कीमत पर, इस अपरिवर्तनीय सुनिश्चित करता है ntire वस्तु। हम इस

struct BigArray{ 
    BigArray():m_data(new int[10000000]){} 
    int operator[](size_t i)const{return (*m_data)[i];} 
    int& operator[](size_t i){return (*m_data)[i];} 
private: 
    shared_ptr<int> m_data; 
}; 

इस तरह एक speedup प्रयास भी अपरिवर्तनीय मिलेंगे गहरी प्रतिलिपि बनाने के बिना हो सकता है, इसलिए सभी अब तक अच्छा है। अब इस नए कार्यान्वयन हम

b[0]=2; 

अब किया का उपयोग कर हम इस गहरी प्रतिलिपि मामले ज़ोर के रूप में ही काम करना चाहते हैं (एक [0] = b [0]!); लेकिन यह विफल रहता है।

struct BigArray{ 
     BigArray():m_data(new int[10000000]){} 
     int operator[](size_t i)const{return (*m_data)[i];} 
     int& operator[](size_t i){ 
      if(!m_data.unique()){//"detach" 
      shared_ptr<int> _tmp(new int[10000000]); 
      memcpy(_tmp.get(),m_data.get(),10000000); 
      m_data=_tmp; 
      } 
      return (*m_data)[i]; 
     } 
    private: 
     shared_ptr<int> m_data; 
    }; 

अब हम एक वर्ग है कि उथले की नकल की है जब केवल स्थिरांक का उपयोग की जरूरत है, और गहरी की नकल की है जब गैर स्थिरांक का उपयोग की जरूरत है है: इसे सुलझाने के लिए हम एक मामूली बदलाव की जरूरत है। यह "shared_data" पॉइंटर अवधारणा के पीछे विचार है। स्थिरांक कॉल नहीं होगा गहरी प्रतिलिपि, (वे इसे "अलग") जबकि गैर स्थिरांक गहरी कॉपी करेगा कि क्या यह साझा किया जाता है। यह भी इतना है कि यह बस के रूप में अच्छी तरह से सूचक लेकिन डेटा की तुलना नहीं है, तो यह है कि इस काम करेगा ऑपरेटर के शीर्ष पर कुछ अर्थ विज्ञान कहते हैं ==:

BigArray b=a;//shallow copy 
assert(a==b);//true 
b[0]=a[0]+1;//deep copy 
b[0]=a[0];//put it back 
assert(a==b);//true 

इस तकनीक को कॉल गाय (लिखें पर कॉपी) और है सी ++ की शुरुआत के बाद से आसपास रहा है। यह भी बेहद भंगुर है - उपर्युक्त उदाहरण काम करता प्रतीत होता है क्योंकि यह छोटा है और इसमें कुछ उपयोग के मामले हैं। व्यवहार में यह शायद ही कभी मुसीबत के लायक है, और वास्तव में C++ 0x गाय तार त्याग दिया है। तो सावधानी के साथ प्रयोग करें।

+0

तो आप यह कह रहे हैं कि डेटा साझा करके उसका क्या मतलब है गाय है, और पॉइंटर साझा करके सरल साझा_प्टर/संदर्भ गिने गए पॉइंटर मुहावरे हैं? –

+0

हां। और यदि आप क्यूटी दस्तावेज़ पढ़ते हैं तो उतना ही कहता है। http://doc.trolltech.com/4.5/qshareddatapointer.html grep "लिखने पर कॉपी" –

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

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