2013-04-30 10 views
7

वस्तु पर विचार करें:कॉन्स्ट शुद्धता shared_ptr

class Obj 
{ 
    public: 
     Obj() : val(new int(1)) {} 
     int& get() {return *val;} 
     const int& get() const {return *val;} 

    private: 
     std::shared_ptr<int> val; 
}; 

जैसी उम्मीद थी, जब वस्तु का निर्माण किया है और प्रतियां वे सब Obj द्वारा उजागर shared_ptr के माध्यम से एक ही मूल्य संशोधित कर सकते हैं बना रहे हैं।

Obj nonconst1; 
    Obj nonconst2(nonconst1); 
    nonconst2.get() = 2; 
    cout << nonconst1.get() << ", " << nonconst2.get() << endl; 

यह भी गैर स्थिरांक, जिसमें यह पढ़ने लेकिन मूल्य के लिए लिख नहीं की अनुमति देता है कि सही बात करने के लिए लगता है से एक से एक const Obj वस्तु कॉपी-निर्माण करने के लिए संभव नहीं है - के रूप में उम्मीद में निम्न कोड परिणाम एक संकलन त्रुटि:

const Obj const1(nonconst1); 
    const1.get() = 3; 

हालांकि यह संभव है स्थिरांक एक है, जो तब मूल्य की अनुमति है संशोधित करने से एक गैर स्थिरांक Obj कॉपी-निर्माण करने के लिए।

Obj nonconst3(const1); 
    nonconst3.get() = 3; 

मेरे लिए यह कॉन्स्ट-सही महसूस नहीं करता है।

क्या इस व्यवहार को रोकने के लिए कोई तरीका है, जबकि अभी भी प्रतिलिपि बनाने वाले को काम करने की इजाजत है? मेरे वास्तविक उपयोग के मामले में, मैं अभी भी ओबीजे के एसडीडी कंटेनरों को संभव बनाना चाहता हूं।

+0

शायद, आपको प्रति-निर्माण संदर्भ लेने वाले प्रति-निर्माता को परिभाषित करना चाहिए ताकि 'const' ऑब्जेक्ट्स की प्रतिलिपि बनाने से बचें? – Nawaz

+0

@ नवाज, यह काम करता है (मुझे एहसास नहीं हुआ था कि एक कॉपी कन्स्ट्रक्टर में गैर-कॉन्स रेफरी का उपयोग करना संभव था)। दुर्भाग्य से मैं अन्य कॉन्स्ट ओब्जे के निर्माण की प्रतिलिपि बनाने में सक्षम होने के लिए कॉन्स ओब्ज को भी पसंद करूंगा लेकिन 'ओबीजे (कॉन्स ओब्जे एंड ओ) कॉन्स' का प्रयास – tangobravo

उत्तर

1

नहीं, जब तक आप shared_ptr<const int> स्टोर नहीं करना चाहते हैं, तब तक कोई भी इसे गैर-कॉन्स्ट के रूप में एक्सेस कर सकता है।

0

मैन्युअल रूप से Obj की प्रतिलिपि बनाने वाले को कार्यान्वित करें जिसे साझा पॉइंटर की सामग्री की प्रतिलिपि बनाना चाहिए। यह const1 की सामग्री को nonconst3 के माध्यम से संशोधित करने से बचाता है, क्योंकि वे विभिन्न int उदाहरणों को इंगित करते हैं।

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

class Obj 
{ 
    public: 
    //... 
    Obj(Obj &o) : val(o.val) {}       // not a deep copy 
    Obj(const Obj &o) : val(std::make_shared(o.get())) {} // deep copy 
    //... 
} 
2

"मेरे लिए यह स्थिरांक-सही महसूस नहीं करता है" अभी तक यह है: आप बस कर रहे हैं एक नॉन कॉस्ट get गैर-कॉन्स Obj पर विधि का आह्वान करना। कुछ गलत नहीं है उसके साथ।

अपने ग्राहकों को क्या तुम सच में व्यवहार आप के बाद कर रहे हैं, तो आप Obj लेकिन फिर करने के लिए एक स्थिरांक प्रॉक्सी की तरह कुछ का उपयोग करने के सकता है की जरूरत है निश्चित रूप से इसे संभाल करने में सक्षम होना चाहिए:

class Obj 
{ 
    //... 
    //original class definition goes here 
    //... 
    friend class ConstObj; 
}; 

class ConstObj 
{ 
    public: 
    ConstObj(const Obj& v) : val(v.val) {} 
    const int& get() const { return *val; } 

    private: 
    std::shared_ptr<int> val; 
}; 

//usage: 
class WorkingWithObj 
{ 
public: 
    WorkingWithObj(); 
    Obj DoSomethingYieldingNonConstObj(); 
    ConstObj DoSomethingYieldingConstObj(); 
}; 

WorkingWithObj w; 
Obj nonconst(w.DoSomethingYieldingNonConstObj()); 
nonconst.get() = 3; 

ConstObj veryconst(nonconst); 
veryconst.get() = 3; //compiler error 

ConstObj alsoconst(w.DoSomethingYieldingConstObj()); 
alsoconst.get() = 3; //compiler error 
+1

संकलित नहीं करता है क्या आप अपना उत्तर थोड़ा और समझा सकते हैं? मुझे 'ओब्ज' और उपयोग पैटर्न में कुछ भी नहीं दिख रहा है? – Nawaz

+0

@ नवाज ने कुछ टिप्पणियां/उपयोग उदाहरण जोड़े। हालांकि मुझे कहना है कि मैं शायद वास्तविक कोड में इस तरह की संरचनाओं का उपयोग कभी नहीं करूंगा .. – stijn

0

नहीं, isn 'टी ... लेकिन आप COW, deep-copy पॉइंटर का उपयोग कर सकते हैं, जब आप value (गैर-कॉन्स गेटर में) लिख सकते हैं।

या, आप copy-ctors लिख सकते हैं (ref के लिए cref गहरी प्रतिलिपि के लिए उथले प्रतिलिपि करें)।

A(A& obj) : pointer(obj.pointer) {} 
    A(const A& obj) : pointer(new int(*obj.pointer)) {} 
1

यह स्थिरता को तोड़ता नहीं है। val द्वारा इंगित पूर्णांक ऑब्जेक्ट एक विशिष्ट वस्तु है, जिसका मूल उद्देश्य मूल स्वामित्व नहीं है। इसके मूल्य को संशोधित करने से Obj ऑब्जेक्ट्स की स्थिति प्रभावित नहीं होती है।

1

Is there a way to prevent this behaviour, whilst still allowing the copy constructor to work? In my real use case, I still want std containers of Obj to be possible.

आप एक const वस्तु से कॉपी करने के लिए एक अलग प्रतिलिपि निर्माता निर्दिष्ट कर सकते हैं - मतलब है कि आप जैसे कर सकते हैं साझा पॉइंटर की प्रतिलिपि बनाने से बचें और इसके बजाय गैर-कॉन्स्ट ऑब्जेक्ट को एक नल पॉइंटर के साथ बनाएं, या आप पॉइंट-टू-नंबर की गहरी प्रतिलिपि बना सकते हैं। हालांकि मैं इस तरह की चीज करने से बहुत सावधान रहूंगा - कॉपी किए गए चर की स्थिरता के आधार पर अलग-अलग व्यवहार प्राप्त करना अजीब बात है - मुझे डर है कि यह आपके प्रोग्राम व्यवहार के बारे में तर्क करना बहुत कठिन होगा। लेकिन, आपको कुछ व्यवहार चुनना चाहिए या वर्तमान व्यवहार को स्वीकार करना चाहिए क्योंकि std::vector<> कभी-कभी प्रतियां बनायेगा - आप इसे अपरिभाषित नहीं छोड़ सकते हैं।

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