2010-04-07 17 views
7

निम्न पर विचार करें:क्या मैं एक निजी कंस्ट्रक्टर के साथ boost :: make_shared का उपयोग कर सकता हूं?

class DirectoryIterator; 

namespace detail { 
    class FileDataProxy; 

    class DirectoryIteratorImpl 
    { 
     friend class DirectoryIterator; 
     friend class FileDataProxy; 

     WIN32_FIND_DATAW currentData; 
     HANDLE hFind; 
     std::wstring root; 

     DirectoryIteratorImpl(); 
     explicit DirectoryIteratorImpl(const std::wstring& pathSpec); 
     void increment(); 
     bool equal(const DirectoryIteratorImpl& other) const; 
    public: 
     ~DirectoryIteratorImpl() {}; 
    }; 

    class FileDataProxy //Serves as a proxy to the WIN32_FIND_DATA struture inside the iterator. 
    { 
     friend class DirectoryIterator; 
     boost::shared_ptr<DirectoryIteratorImpl> iteratorSource; 
     FileDataProxy(boost::shared_ptr<DirectoryIteratorImpl> parent) : iteratorSource(parent) {}; 
    public: 
     std::wstring GetFolderPath() const { 
      return iteratorSource->root; 
     } 
    }; 
} 

class DirectoryIterator : public boost::iterator_facade<DirectoryIterator, detail::FileDataProxy, std::input_iterator_tag> 
{ 
    friend class boost::iterator_core_access; 
    boost::shared_ptr<detail::DirectoryIteratorImpl> impl; 
    void increment() { 
     impl->increment(); 
    }; 
    bool equal(const DirectoryIterator& other) const { 
     return impl->equal(*other.impl); 
    }; 
    detail::FileDataProxy dereference() const { 
     return detail::FileDataProxy(impl); 
    }; 
public: 
    DirectoryIterator() { 
     impl = boost::make_shared<detail::DirectoryIteratorImpl>(); 
    }; 
}; 

ऐसा लगता है जैसे DirectoryIterator boost::make_shared<DirectoryIteratorImpl> को कॉल करने में सक्षम होना चाहिए, क्योंकि यह DirectoryIteratorImpl का मित्र है। हालांकि, यह कोड संकलित करने में विफल रहता है क्योंकि DirectoryIteratorImpl के लिए निर्माता निजी है।

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

क्या यह make_shared के आसपास मेरी मूलभूत गलतफहमी है या क्या मुझे संकलित करने के लिए friend के रूप में कुछ प्रकार के बूस्ट टुकड़े को चिह्नित करने की आवश्यकता है?

+0

क्या आप वाकई अपने impl सूचक के लिए shared_ptr की आवश्यकता है? boost :: scoped_ptr आमतौर पर अधिक उपयुक्त है और चीजों को अधिक सरल बनाता है। Shared_ptr आमतौर पर केवल इस मामले में उपयोग किया जाएगा यदि आप निर्देशिकाइंटर को प्रतिलिपि बनाना चाहते थे और प्रतियों को एक एकल इंपोर्ट उदाहरण साझा करना चाहिए। आपके द्वारा पोस्ट किए गए कोड में, ऐसा लगता है कि एक इंपोर्ट साझा करने वाली प्रतियां एक त्रुटि होगी। Shared_ptr तब होता है जब एकाधिक पॉइंटर्स को किसी उदाहरण के स्वामित्व को साझा करना चाहिए। – Alan

उत्तर

5

आपको इसके लिए कुछ बूस्ट टुकड़े दोस्त बनाने की आवश्यकता होगी। मूल रूप से make_shared कन्स्ट्रक्टर को कॉल कर रहा है और तथ्य यह है कि यह किसी मित्र फ़ंक्शन के भीतर से किया जाता है, इससे कंपाइलर के लिए कोई फर्क नहीं पड़ता।

अच्छी खबर यह है कि make_shared कन्स्ट्रक्टर को कॉल कर रहा है, कोई अन्य टुकड़ा नहीं। तो बस make_shared दोस्त बनाना काम करेगा ... हालांकि इसका मतलब है कि कोई भी shared_ptr<DirectoryIteratorImpl> बना सकता है ...

+1

हम्म ... यह नरक के रूप में परेशान है :) धन्यवाद! –

+0

'make_shared' की समस्या यह है कि यह स्मृति के एक ब्लॉक को आवंटित करता है और फिर नियुक्ति' नया 'का उपयोग करता है, यही कारण है कि इसे स्वयं को कन्स्ट्रक्टर का आह्वान करना पड़ता है। मैं सहमत हूं कि आपकी समस्या के संबंध में यह परेशान है। –

+1

ऐसा करने में समस्या यह है कि यदि आप TR1 या C++ 0x पर माइग्रेट करते हैं, या भले ही बूस्ट अपडेट जारी करता है, तो आपको कोई गारंटी नहीं है कि यह अभी भी काम करेगा। – dvide

4

क्या कोई अच्छा कारण नहीं है कि पुराने पुराने shared_ptr कन्स्ट्रक्टर का उपयोग न करें? (यदि वहाँ एक है, आप make_shared कार्यान्वयन पर एक नज़र लेने के लिए चाहते हैं और यह कर सकते हैं)

DirectoryIterator() 
    : impl(new detail::DirectoryIteratorImpl()) 
{} 

इस तरह पहले से ही बिना खोले ही DirectoryIteratorImpl के मित्र हैं कि निर्माता करने के लिए कॉल DirectoryIterator वर्ग से बनाया गया है अन्य सभी कोड के लिए दरवाजा।

+0

नहीं, इसमें कुछ भी गलत नहीं है। लेकिन मुझे http://stackoverflow.com/questions/2569046/is-there-a-way-to-increase-the- कार्यक्षमता-of-shared-ptr-by-storing-the- पर 'make_shared' का उपयोग करने के लिए कहा गया था। संदर्भ/2569211 # 2569211। जैसा कि मैंने अभी सुझाव दिया है, वही है जो आपने अभी किया है। +1 –

+1

'मेक_श्रेर्ड' इसकी मेमोरी आवंटन में अधिक कुशल है ... (कम विखंडन, अधिक गति) –

+1

मुझे स्मृति विखंडन (आपको वास्तव में आश्वस्त होना चाहिए) के बारे में पता है, लेकिन मैंने कभी-कभी पढ़ा (वास्तव में यहां SO में): * वह जो प्रदर्शन के लिए शुद्धता बलिदान देता है न तो *, जो एक अच्छा आदर्श वाक्य है। और मूल लिंक किए गए प्रश्न में, बिली मानते हैं कि उन्हें प्रदर्शन की आवश्यकता नहीं है। यदि कन्स्ट्रक्टर निजी है, तो 'make_shared' एक दोस्त नहीं होना चाहिए (जो वास्तव में किसी को' make_shared' 'के माध्यम से ऑब्जेक्ट बनाने की इजाजत देकर encapsulation को तोड़ने के करीब है) –

0

आप अपनी कक्षा को इंटरफेस भाग और कार्यान्वयन भाग में विभाजित कर सकते हैं। इंटरफ़ेस भाग सार्वजनिक किया गया है, और कार्यान्वयन भाग में सार्वजनिक निर्माता हो सकते हैं। हालांकि, इसका मतलब है कि आपको वर्चुअल विरासत का उपयोग करना होगा।