2017-05-28 51 views
15

shared_ptr जैसी कक्षाओं को उनके रचनाकारों में एक और टेम्पलेट क्यों है?सामान्यीकृत प्रतिलिपि बनाने वाले

उदाहरण के लिए:

template<class T> class shared_ptr { 
public: 
    template<class Y> 
    explicit shared_ptr(Y * p); 

मैं स्कॉट Meyers के प्रभावी सी ++, मद 45 है, जो कहते हैं कि यह पीछे विचार यह उन के माध्यम से बहुरूपता संभव बनाने के लिए है पढ़ने किया गया है; जो है, shared_ptr<B> से shared_ptr<A> निर्माण बी ए

से ली गई है लेकिन

explicit shared_ptr(T * p); 

काफी की तरह एक निर्माता को परिभाषित नहीं कर रहा है तो क्या होगा? मेरा मतलब है, इस कोड को बस ठीक काम करता है:

class C1 { 
}; 

class C2 : public C1 { 
}; 

template<typename T> 
class A 
{ 
public: 
    A(T &a) 
    { 
    var1 = a; 
    } 

    T var1; 
}; 

int main(int argc, char *argv[]) 
{ 
    C2 c2; 
    A<C1> inst1(c2); 
} 

तो क्यों न हम वहाँ निर्माता के लिए एक और टेम्पलेट की जरूरत है? केवल एक Base* लेता

#include <memory> 

class Base {}; 
class Derived : public Base {}; 

int main() { 
    std::shared_ptr<Base> ptr(new Derived); 
} 

तो shared_ptr, यह अंततः कि Base* सूचक पर delete कॉल करने के लिए मजबूर किया जाता है:

+4

क्या होगा यदि दो प्रकार विरासत का उपयोग करके एक-दूसरे से प्राप्त नहीं होते हैं, लेकिन वे एक दूसरे के बीच * परिवर्तनीय * हैं? –

+1

@ सोप्रप्रोग्रामड्यूड अगर वे एक दूसरे के लिए परिवर्तनीय हैं, तो मेरा समाधान नहीं होगा 'वैसे भी काम करते हैं?चूंकि कक्षा को किसी प्रकार के लिए तत्काल किया जाएगा और नियमित रूपांतरण होगा, क्योंकि यह कुछ टी का एक ठोस वर्ग था? –

+1

भले ही विभिन्न प्रकार की दो वस्तुओं को एक-दूसरे के बीच परिवर्तित किया जा सके, फिर भी प्रकार अलग-अलग हैं। इसका मतलब यह होगा कि टेम्पलेट पैरामीटर 'टी' को दो अलग-अलग प्रकारों का प्रतिनिधित्व करना होगा, जो संभव नहीं है। –

उत्तर

13

टेम्पलेट निर्माता के बिना, निम्नलिखित कोड अपरिभाषित व्यवहार होगा। लेकिन चूंकि Base में वर्चुअल विनाशक नहीं है और पॉइंटर वास्तव में Derived पर इंगित करता है, यह अपरिभाषित व्यवहार है।

लेकिन वास्तव में, उपरोक्त कोड अच्छी तरह से गठित है। shared_ptr के लिए टेम्पलेट कन्स्ट्रक्टर Derived* पॉइंटर लेता है और एक कस्टम डिलीटर स्टोर करता है जो को Derived* पॉइंटर पर कॉल करता है, जो ठीक है।

+2

मुझे लगता है कि यह एक अच्छा स्पष्टीकरण है कि यह 'std :: shared_ptr' के लिए क्यों जरूरी है, लेकिन मुझे लगता है कि यह पैटर्न मानक पुस्तकालय के अन्य स्थानों में आम है जहां डिलीटर की आवश्यकता नहीं है। –

+2

यह कस्टम डिलीटर होने का एक मामूली साइड इफेक्ट है। वे एक अच्छा अतिरिक्त हैं और share_ptr के पीछे प्रेरक बल नहीं है (जो * पोंटे * साझा कर रहा है)। –

+0

@ एनएम .: एक subobject करने के लिए 'shared_ptr' रखने की क्षमता और पूर्ण ऑब्जेक्ट के एक आजीवन प्रबंधन जीवनकाल' shared_ptr' की एक बहुत शक्तिशाली क्षमता है। बेस सबोबजेक्ट्स केवल एक विशेष मामला है, क्षमता में सदस्य सबोबजेक्ट्स और यहां तक ​​कि "स्वामित्व" सहकर्मी वस्तुओं को भी शामिल किया गया है। –

0
explicit shared_ptr(T * p); 

तो shared_ptr केवल इस निर्माता था, यह अपने पूरे उद्देश्य, एक संदर्भ बार गणना सूचक प्रदान करना है जो हार जाएगा।

संदर्भ गणना (या इसके बजाय एक सूचक) shared_ptr का एक हिस्सा है। इसे हर बार shared_ptr बनाया, नष्ट या कॉपी किया जाना चाहिए। और यह अंतिम भाग केवल तभी हासिल किया जा सकता है जब shared_ptr प्रतिलिपि दिनचर्या में पास हो जाए। एक नंगे सूचक को पास करने के लिए shared_ptr की संदर्भ संख्या

एक संदर्भ-गणना सूचक केवल तभी साझा किया जाता है जब इसकी संदर्भ संख्या 1 से अधिक हो जाती है। आपकी योजना के साथ यह स्पष्ट नहीं होता कि यह कभी भी होने वाला माना जाता है।

कुछ संदर्भ-गणना कार्यक्षमता सामान्य (गैर-टेम्पलेट) प्रतिलिपि निर्माता द्वारा प्रदान की जाती है। लेकिन यह सब नहीं।

उदाहरण के लिए

,

std::shared_ptr<Derived> d; 
std_shared_ptr<Base> b; 
... 
b = d; 

टेम्पलेट "कॉपी 'निर्माता के बिना संकलित करने के लिए विफल हो जाएगा। हम साझा poiters सामान्य संकेत के रूप में ही बहुरूपी व्यवहार प्रदान करना चाहते हैं, तो हम बस काम करने के लिए ऊपर निर्माण चाहते हैं। एक टेम्पलेट कन्स्ट्रक्टर यह प्रदान करता है।

+1

मुझे लगता है कि सवाल यह है कि हमारे पास 'टेम्पलेट स्पष्ट साझा_ptr (वाई *) है; ', क्यों नहीं, हमने' shared_ptr (const shared_ptr &); 'और' टेम्पलेट shared_ptr (const shared_ptr &); '। – aschepler

+0

@aschepler मुझे नहीं लगता कि इस सवाल को पूरी जागरूकता में पूछा गया है कि क्यों 'shared_ptr' को एक सामान्य प्रतिलिपि बनाने की आवश्यकता है। मैं वैसे भी कुछ स्पष्टीकरण जोड़ दूंगा। –

+0

@ एनएम। प्रतिक्रिया के लिए सभी धन्यवाद। लेकिन, उन स्मार्ट पॉइंटर्स के पीछे कुछ अतिरिक्त कार्यक्षमताओं के साथ सामान्य पॉइंटर्स की तरह व्यवहार करने का विचार नहीं है? (उदाहरण के लिए गिनती गिनती)। आपके द्वारा लिखे गए कोड, मुझे लगता है कि उनमें से एक 'डी' –

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