2010-01-17 21 views
37

मेरे पास कक्षा में कुछ कंटेनर हैं, उदाहरण के लिए, वेक्टर या मानचित्र जिसमें साझा_प्टर के ढेर पर रहने वाले ऑब्जेक्ट्स हैं।सी ++ स्मार्ट पॉइंटर कॉन्स शुद्धता

उदाहरण

template <typename T> 
class MyExample 
{ 
public: 

private: 
vector<tr1::shared_ptr<T> > vec; 
map<tr1::shared_ptr<T> , int> h; 
}; 

मैं इस वर्ग है कि कभी कभी (shared_ptr<const T> के माध्यम से) shared_ptrs रिटर्न वस्तुओं const के सार्वजनिक इंटरफेस और है के लिए कभी कभी shared_ptr<T> जहां मैं फोन करने वाले वस्तुओं उत्परिवर्तित करने के लिए अनुमति देते हैं। मुझे लॉजिकल कॉन्स शुद्धता चाहिए, इसलिए यदि मैं को कॉन्स्ट के रूप में एक विधि चिह्नित करता हूं, तो यह ढेर पर ऑब्जेक्ट्स को नहीं बदल सकता है।

सवाल:

1) मैं tr1::shared_ptr<const T> और tr1::shared_ptr<T> की परस्पर से उलझन में हूँ। जब कोई वर्ग में एक shared_ptr<const T> shared_ptr गुजरता है, मैं एक shared_ptr<T> या shared_ptr<const T> वेक्टर के अंदर के रूप में संग्रहीत और नक्शा या मैं नक्शा, वेक्टर प्रकार परिवर्तित करते हैं (जैसे insert_elemeent (shared_ptr<const T> obj)?

2) यह है निम्नानुसार कक्षाओं को तुरंत चालू करने के लिए बेहतर: MyExample<const int>? ऐसा लगता है कि अनन्य प्रतिबंधित है, क्योंकि मैं कभी भी shared_ptr<int> वापस नहीं कर सकता?

tr1::shared_ptr<const T>T const * की कार्यक्षमता यह अर्थात् क्या कहते हैं स्थिरांक है नकल उतार रहा है, लेकिन सूचक ही नहीं है:

उत्तर

3

एक बात को एहसास है कि है।

तो आप अपने साझा सूचक को एक नया मान असाइन कर सकते हैं, लेकिन मुझे उम्मीद है कि आप डी-रेफरेंस shared_ptr को एल-वैल्यू के रूप में उपयोग नहीं कर पाएंगे।

+1

"एल-वैल्यू।" एक एल-वैल्यू असाइन करने योग्य नहीं है! – curiousguy

5

अगर कोई आपको shared_ptr<const T> पास करता है तो आपको कभी भी T संशोधित करने में सक्षम नहीं होना चाहिए। यह निश्चित रूप से const T को केवल T पर डालने के लिए तकनीकी रूप से संभव है, लेकिन यह Tconst बनाने के इरादे को तोड़ देता है। इसलिए यदि आप चाहते हैं कि लोग आपकी कक्षा में ऑब्जेक्ट्स जोड़ने में सक्षम हों, तो उन्हें आपको shared_ptr<T> और shared_ptr<const T> देना चाहिए। जब आप अपनी कक्षा से चीजें वापस करते हैं तो आप संशोधित नहीं करना चाहते हैं, यह तब होता है जब आप shared_ptr<const T> का उपयोग करते हैं।

shared_ptr<T> स्वचालित रूप से shared_ptr<const T> पर स्वचालित रूप से परिवर्तित किया जा सकता है लेकिन दूसरी तरफ नहीं। const विधियों के उदार उपयोग करने के लिए यह आपकी मदद कर सकता है (और आपको इसे वैसे भी करना चाहिए)। जब आप कक्षा विधि const परिभाषित करते हैं, तो संकलक आपको अपने किसी भी डेटा सदस्यों को संशोधित करने या const T को छोड़कर कुछ भी वापस नहीं करने देगा। तो इन तरीकों का उपयोग करने से आप यह सुनिश्चित करने में मदद करेंगे कि आपने कुछ नहीं भूलया है, और आपकी कक्षा के उपयोगकर्ताओं को यह समझने में मदद मिलेगी कि विधि का इरादा क्या है। (उदाहरण: virtual shared_ptr<const T> myGetSharedPtr(int index) const;)

आप अपने दूसरे बयान पर सही हैं, तो आप शायद नहीं <const T> के रूप में अपने वर्ग का दृष्टांत करना चाहते हैं, क्योंकि आप अपने T रों में से किसी को संशोधित करने में सक्षम नहीं होगा।

34

shared_ptr<T> और shared_ptr<const T> इंटरचेंज योग्य नहीं हैं। यह एक तरीका है - shared_ptr<T> परिवर्तनीय है shared_ptr<const T> लेकिन रिवर्स नहीं।

का निरीक्षण करें:

// f.cpp 

#include <memory> 

int main() 
{ 
    using namespace std; 

    shared_ptr<int> pint(new int(4)); // normal shared_ptr 
    shared_ptr<const int> pcint = pint; // shared_ptr<const T> from shared_ptr<T> 
    shared_ptr<int> pint2 = pcint; // error! comment out to compile 
} 

संकलन के माध्यम से

सीएल/EHsc f.cpp

तुम भी एक constness के आधार पर एक समारोह को ओवरलोड कर सकते हैं। आप जो भी चाहते हैं उसे करने के लिए आप इन दो तथ्यों को करने के लिए गठबंधन कर सकते हैं।

आपके दूसरे प्रश्न के लिए, MyExample<int> शायद MyExample<const int> से अधिक समझ में आता है।

11

मैं निम्नलिखित methotology सुझाव है:

template <typename T> 
class MyExample 
{ 
    private: 
    vector<shared_ptr<T> > data; 

    public: 
    shared_ptr<const T> get(int idx) const 
    { 
     return data[idx]; 
    } 
    shared_ptr<T> get(int idx) 
    { 
     return data[idx]; 
    } 
    void add(shared_ptr<T> value) 
    { 
     data.push_back(value); 
    } 
}; 

यह स्थिरांक-शुद्धता सुनिश्चित करता है। जैसा कि आप देखते हैं कि ऐड() विधि < कॉन्स टी> लेकिन < टी> का उपयोग नहीं करती है क्योंकि आप कक्षा को टीएस कॉन्स्ट टीएस स्टोर करने का इरादा रखते हैं। लेकिन जब इसे कॉन्स एक्सेस किया जाता है, तो आप < कॉन्स्ट टी> वापस लौटते हैं, जो साझा नहीं है क्योंकि shared_ptr < टी> आसानी से shared_ptr < कॉन्स्ट टी> में परिवर्तित किया जा सकता है। और sice दोनों() विधियों को आपके आंतरिक भंडारण में shared_ptr की प्रतियां वापस प्राप्त करते हैं, कॉलर आपके आंतरिक पॉइंटर्स को ऑब्जेक्ट को गलती से बदल नहीं सकता है। यह सब गैर-स्मार्ट सूचक संस्करण से तुलनीय है:

template <typename T> 
class MyExamplePtr 
{ 
    private: 
    vector<T *> data; 

    public: 
    const T *get(int idx) const 
    { 
     return data[idx]; 
    } 
    T *get(int idx) 
    { 
     return data[idx]; 
    } 
    void add(T *value) 
    { 
     data.push_back(value); 
    } 
}; 
+0

क्या यह नहीं होना चाहिए कि 'shared_ptr ' आसानी से को shared_ptr 'और अन्य तरीकों से आसानी से परिवर्तित किया जा सकता है? – user231536

+0

जब एक साधारण सदस्य लौटते हैं तो ओवरलोडिंग एक बड़ा सौदा नहीं लगता है। लेकिन क्या होगा यदि आप 'वेक्टर' से 'shared_ptr' वापस करते हैं - जहां आपको गणना करना है कि कौन सा सही है। आप कोड डुप्लिकेशन से कैसे बचते हैं? – thomthom

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