2010-10-10 12 views
73

Mr. Lidström and I had an argument :)shared_ptr जादू :)

श्री Lidström के दावे कि एक निर्माण shared_ptr<Base> p(new Derived); बेस की आवश्यकता नहीं है एक आभासी नाशक है:

आर्मेन Tsirunyan: "वास्तव में विल shared_ptr सही ढंग से साफ करें? क्या आप इस मामले में कृपया दिखा सकते हैं कि यह प्रभाव कैसे लागू किया जा सकता है? "

डैनियल Lidström: "shared_ptr कंक्रीट उदाहरण नष्ट करने के लिए अपने स्वयं के नाशक का उपयोग करता है यह सी ++ समुदाय के भीतर आरए II के रूप में जाना जाता है मेरी सलाह है कि आप सभी आप आरए II के बारे में कर सकते हैं सीखना है यह कर देगा अपने।।। जब आप सभी परिस्थितियों में आरएआईआई का उपयोग करते हैं तो सी ++ कोडिंग बहुत आसान होती है। "

आर्मेन Tsirunyan: "मैं आरए II के बारे में पता है, और मैं भी जब PN 0. तक पहुँच जाता है कि अंततः shared_ptr नाशक संग्रहीत पिक्सल हटा सकते हैं पता है लेकिन अगर पिक्सल को Base और गतिशील प्रकार सूचक को स्थिर प्रकार सूचक था Derived, तब तक Base में एक आभासी विनाशक है, इसके परिणामस्वरूप अपरिभाषित व्यवहार होगा। अगर मैं गलत हूं तो मुझे सही करें। "

डैनियल Lidström: "shared_ptr जानता स्थिर प्रकार कंक्रीट है यह इस जानता है के बाद से मैं अपने निर्माता में इसे पारित जादू की तरह एक सा लगता है, लेकिन मैं इसे डिजाइन और अत्यंत अच्छा कर रहा है आपको विश्वास दिलाता कर सकते हैं।! । "

तो, हमें न्याय करें। साझा_ptr को वर्चुअल विनाशक रखने के लिए पॉलिमॉर्फिक कक्षाओं की आवश्यकता के बिना यह कैसे संभव है (यदि यह है)? अग्रिम

+3

आप [मूल धागे] (http://stackoverflow.com/questions/3899688/default-virtual-dtor/3899726) से लिंक कर सकते थे। –

+0

@ डारिन: मैंने यह किया। – sbi

+7

एक और दिलचस्प बात यह है कि 'shared_ptr पी (नया व्युत्पन्न) '' व्युत्पन्न' वस्तु को इसके विनाशक द्वारा भी नष्ट कर देगा, भले ही यह 'वर्चुअल' है या नहीं। – dalle

उत्तर

66

हां, इस तरह shared_ptr को लागू करना संभव है। बूस्ट करता है और सी ++ 11 मानक को भी इस व्यवहार की आवश्यकता होती है। एक अतिरिक्त लचीलापन के रूप में shared_ptr सिर्फ संदर्भ काउंटर से अधिक प्रबंधित करता है।एक तथाकथित डिलीटर आमतौर पर उसी स्मृति ब्लॉक में डाल दिया जाता है जिसमें संदर्भ काउंटर भी होते हैं। लेकिन मजेदार हिस्सा यह है कि इस डिलीटर का प्रकार shared_ptr प्रकार का हिस्सा नहीं है। इसे "टाइप एरर" कहा जाता है और मूल रूप से वही तकनीक है जो वास्तविक पॉलक्टर के प्रकार को छिपाने के लिए "पॉलिमॉर्फिक फ़ंक्शन" बूस्ट :: फ़ंक्शन या std :: फ़ंक्शन को लागू करने के लिए उपयोग की जाती है। अपने उदाहरण के काम करने के लिए, हम एक टेम्प्लेटेड निर्माता की जरूरत है:,

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

तो अगर आप अपनी कक्षाओं बेस के साथ इस का उपयोग करें और व्युत्पन्न ...

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

int main() { 
    shared_ptr<Base> sp (new Derived); 
} 

... वाई के साथ टेम्प्लेटेड निर्माता = व्युत्पन्न का उपयोग shared_ptr ऑब्जेक्ट को बनाने के लिए किया जाता है। इस प्रकार कन्स्ट्रक्टर को उचित डिलीटर ऑब्जेक्ट और संदर्भ काउंटर बनाने का मौका मिला है और डेटा नियंत्रक के रूप में इस नियंत्रण ब्लॉक में एक पॉइंटर स्टोर करता है। यदि संदर्भ काउंटर शून्य तक पहुंचता है, तो पहले बनाए गए और व्युत्पन्न-जागरूक डिलीटर का उपयोग ऑब्जेक्ट का निपटान करने के लिए किया जाएगा।

आवश्यक है::pT* के लिए परिवर्तनीय होना चाहिए

सी ++ 11 मानक इस निर्माता (20.7.2.2.1) के बारे में कहने के लिए निम्न है। Y एक पूर्ण प्रकार का होगा। अभिव्यक्ति delete p अच्छी तरह से गठित की जाएगी, अच्छी तरह से परिभाषित व्यवहार होगा और अपवाद नहीं फेंक देगा।

प्रभाव: निर्माणों एक shared_ptr वस्तु कि मालिक सूचक p

...

और नाशक (20.7.2.2.2) के लिए:

प्रभाव: तो *thisखाली या शेयरों एक और shared_ptr उदाहरण के साथ स्वामित्व है (use_count() > 1) , कोई दुष्प्रभाव नहीं हैं। अन्यथा, यदि *this किसी ऑब्जेक्ट का मालिक है p और d, d(p) को हटा दें। अन्यथा, यदि *this एक सूचक p का मालिक है, और delete p कहा जाता है।

(बोल्ड फ़ॉन्ट का उपयोग करने पर जोर मेरा है)।

+0

+1। – legends2k

+0

'आने वाले मानक को भी इस व्यवहार की आवश्यकता है: (ए) कौन सा मानक और (बी) क्या आप कृपया संदर्भ (मानक के लिए) प्रदान कर सकते हैं? – kevinarpe

13

सीधे शब्दों में धन्यवाद,

shared_ptr कि निर्माता द्वारा बनाई गई है विशेष Deleter समारोह है कि हमेशा दिया वस्तु का नाशक और न बेस के नाशक का उपयोग करता है का उपयोग करता है, इस टेम्पलेट मेटा के साथ काम करने का एक सा है प्रोग्रामिंग, लेकिन यह काम करता है।

कुछ ऐसा

template<typename SomeType> 
shared_ptr(SomeType *p) 
{ 
    this->destroyer = destroyer_function<SomeType>(p); 
    ... 
} 
+0

हम्म ... दिलचस्प, मैं इस पर विश्वास करना शुरू कर रहा हूं :) –

+1

@ आर्मेन Tsirunyan आप चर्चा शुरू करने से पहले साझा_ptr के डिजाइन विवरण में देखा जाना चाहिए था। यह 'डिलीटर का कब्जा' share_ptr की आवश्यक विशेषताओं में से एक है ... –

+5

@ paul_71: मैं आपसे सहमत हूं। दूसरी ओर मेरा मानना ​​है कि यह चर्चा न केवल मेरे लिए उपयोगी थी, बल्कि अन्य लोगों के लिए भी जो इस तथ्य को share_ptr के बारे में नहीं जानते थे। तो मुझे लगता है कि यह धागा किसी भी तरह से शुरू करने के लिए एक महान पाप नहीं था :) –

26

की तरह जब shared_ptr यह बनाई गई है अंदर ही Deleter वस्तु संग्रहीत करता है। इस ऑब्जेक्ट को तब कहा जाता है जब shared_ptr पॉइंट संसाधन को मुक्त करने वाला है। चूंकि आप जानते हैं कि निर्माण के बिंदु पर संसाधन को कैसे नष्ट किया जाए, आप अधूरे प्रकारों के साथ shared_ptr का उपयोग कर सकते हैं। जो कोई भी साझा_प्टर बनाया है वहां एक सही डिलीटर संग्रहीत किया गया है।

उदाहरण के लिए, आप एक कस्टम Deleter बना सकते हैं:

void DeleteDerived(Derived* d) { delete d; } // EDIT: no conversion needed. 

shared_ptr<Base> p(new Derived, DeleteDerived); 

पी उठाई वस्तु को नष्ट करने के DeleteDerived कॉल करेंगे। कार्यान्वयन यह स्वचालित रूप से करता है।

+4

+1 अपूर्ण प्रकारों के बारे में टिप्पणी के लिए +1, एक विशेषता के रूप में 'shared_ptr' का उपयोग करते समय बहुत आसान है। टाइप एरर होने के लिए कोड स्निपेट के लिए –