2010-09-25 14 views
8

मुझे हाल ही में auto_ptr और shared_ptr के अस्तित्व के साथ पेश किया गया था और मेरे पास एक बहुत ही सरल/निष्पक्ष प्रश्न है।प्वाइंटर्स बनाम auto_ptr बनाम shared_ptr

मैं डेटा संरचना को लागू करने का प्रयास करता हूं और मुझे Node के बच्चों को इंगित करने की आवश्यकता है (जो 1 से अधिक हैं और इसकी संख्या) बदल सकती है। जो सबसे अच्छा विकल्प है और क्यों है:

class Node 
{ 
    public: 
     // ... 
     Node *children; 

    private: 
     //... 
} 

class Node 
{ 
    public: 
     // ... 
     share_ptr<Node> children; 

    private: 
     //... 
} 

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

+0

auto_ptr में हटाई गई है सी ++ 11 और पुराने सी ++ संस्करण में कोड में यदि संभव हो तो साथ ही बचा जाना चाहिए। – Nikko

+0

'auto_ptr' को बहिष्कृत किया गया है क्योंकि यह अनावश्यक रूप से उपयोग करने के लिए अनावश्यक रूप से कठिन है। इसके बजाय 'unique_ptr' का उपयोग करें जो मूल रूप से' auto_ptr' जैसा ही है, बस यह सही ढंग से काम करता है और सरणी का भी समर्थन करता है। यह सी ++ 11 के बाद उपलब्ध है। – nwp

+0

पर भी एक नजर डालें http://stackoverflow.com/questions/3987521/how-bad-is-to-use-void-pointer-in-stdvector-declaration – fizzbuzz

उत्तर

7

आप सही हैं कि auto_ptr सरणी के लिए काम नहीं करता है। जब यह ऑब्जेक्ट को नष्ट कर देता है, तो यह delete object; का उपयोग करता है, इसलिए यदि आपने new objects[whatever]; का उपयोग किया है, तो आपको अपरिभाषित व्यवहार मिलेगा। शायद थोड़ा और अधिक, auto_ptr "कॉपी करने योग्य" (मानक मानक को परिभाषित करता है) की आवश्यकताओं को पूरा नहीं करता है, इसलिए आप auto_ptr के कंटेनर (वेक्टर, डेक, सूची इत्यादि) नहीं बना सकते हैं।

shared_ptr एक ही ऑब्जेक्ट के लिए भी है। यह ऐसी स्थिति के लिए है जहां आपने स्वामित्व साझा किया है और केवल सभी मालिकों को दायरे से बाहर जाने पर ऑब्जेक्ट को हटाने की आवश्यकता है। जब तक कि कुछ ऐसा नहीं हो रहा है, आपने हमें बताया नहीं है, संभावनाएं बहुत अच्छी हैं कि यह आपकी आवश्यकताओं को अच्छी तरह से फिट नहीं करती है।

आप शायद एक और कक्षा देखना चाहते हैं जो आपके लिए नया हो: ptr_vector को बढ़ावा दें। कम से कम आपने जो कहा है उसके आधार पर, यह आपकी आवश्यकताओं को auto_ptr या shared_ptr से बेहतर मानता है।

+0

धन्यवाद! तो मुझे लगता है कि मुझे या तो 'ptr_vector' या' नोड * बच्चों 'के साथ जाना चाहिए। 'नोड' के 'std :: vector' को इंगित करने के लिए मैं 'auto_ptr' का उपयोग नहीं कर सका? इसके अलावा, 'नोड * बच्चों' सही है या मुझे 'नोड ** बच्चों' पसंद करना चाहिए? मैं थोड़ा असमंजस में हूँ। यहां बहुत सारे प्रश्न पैक करने के लिए खेद है। –

+0

@ माइल: आप जो कर रहे हैं उसके बारे में और जानने के बिना, यह सुनिश्चित करना मुश्किल है। असल में, एक 'नोड *' आपको नोड्स की मनमानी संख्या के लिए एक बिंदु देगा, इसलिए उन नोड्स मूल रूप से उनके माता-पिता का हिस्सा होंगे, न केवल उससे जुड़े हुए हैं। एक 'नोड **' आपको नोड्स के पॉइंटर्स की गतिशील सरणी देगा, लेकिन आपको गतिशील सरणी का प्रबंधन करना होगा। –

3

मैंने std::vector<std::shared_ptr<Node> > children सफलतापूर्वक इसी तरह की स्थिति में उपयोग किया है।

सरणी के बजाय shared_ptrs के वेक्टर का उपयोग करने का मुख्य लाभ यह है कि संसाधन संसाधन प्रबंधन आपके लिए संभाला जाता है। यह विशेष रूप से दो परिस्थितियों में आसान है:
1) जब वेक्टर अब दायरे में नहीं है, तो यह स्वचालित रूप से इसकी सभी सामग्री पर हटा देता है। इस मामले में, बच्चे नोड की संदर्भ संख्या 1 से गिर जाएगी और यदि कुछ भी इसका संदर्भ नहीं दे रहा है, तो ऑब्जेक्ट पर हटा दिया जाएगा।
2) यदि आप कहीं और नोड का संदर्भ दे रहे हैं, तो किसी हटाए गए ऑब्जेक्ट पर लटकते पॉइंटर के साथ छोड़ा जाने का कोई जोखिम नहीं है। ऑब्जेक्ट केवल तभी हटा दिया जाएगा जब इसमें कोई और संदर्भ न हो।

जब तक आप ऐसा व्यवहार नहीं चाहते हैं जो काफी जटिल है (शायद एक कारण है कि एक सरणी आवश्यक क्यों है), तो मैं सुझाव दूंगा कि यह आपके लिए एक अच्छा दृष्टिकोण हो सकता है।

विचार का एक सरल कार्यान्वयन:

class Node { 
private: 
    T contents; 
    std::vector<std::shared_ptr<Node> > children; 

public: 
    Node(T value) : contents(value) {}; 

    void add_child(T value) { 
     auto p = std::make_shared<Node>(value); 
     children.push_back(p); 
    } 

    std::shared_ptr<Node> get_child(size_t index) { 
     // Returning a shared pointer ensures the node isn't deleted 
     // while it is still in use. 
     return children.at(index); 
    } 

    void remove_child(size_t index) { 
     // The whole branch will be destroyed automatically. 
     // If part of the tree is still needed (eg. for undo), the 
     // shared pointer will ensure it is not destroyed. 
     children.erase(children.begin() + index); 
    } 

}; 
+0

यह भी ध्यान दें कि आप अपने स्वयं के विनाशक को shared_ptr पर प्रदान कर सकते हैं ताकि आप सादे हटाने के बजाय हटाए गए [] को कॉल करके एक सरणी प्रबंधित करने के लिए उपयोग कर सकें। – QuesterZen

+0

सरणी के लिए कस्टम डिलीटर जोड़ने का सबसे सरल (लेकिन थोड़ा बदसूरत) तरीका लैम्ब्डा फ़ंक्शन का उपयोग करना है, जिसे कन्स्ट्रक्टर में अतिरिक्त तर्क के रूप में पारित किया जाता है। उदाहरण: 'std :: shared_ptr sp (नया टी [एन], [] (टी * पी) {हटाएं [] पी;})'। Unique_ptrs के लिए इसके लिए एक विशेष संस्करण प्रदान किया गया है: 'std :: unique_ptr अप (नया टी [एन])' जो हटाए जाने के बजाय हटाएं [] को कॉल करता है। – QuesterZen

1

auto_ptrstd::unique_ptr और btw के पक्ष में पदावनत किया गया है। std::unique_ptr सरणी के लिए काम करता है। आपको बस सी ++ 11 समर्थन की आवश्यकता है। और स्मार्ट पॉइंटर्स के बारे में पहले से ही बहुत सारे संसाधन हैं और वहां से अर्थशास्त्र चलाते हैं। auto_ptr और unique_ptr के बीच मुख्य अंतर है जब आप प्रतिलिपि निर्माता फोन और unique_ptr प्रतिलिपि निर्माता मनाही कि auto_ptr एक कदम करता है, लेकिन एक move जब इस कदम निर्माता बुला अनुमति देता है। इसलिए आपको चाल semantics के साथ सी ++ 11 समर्थन की जरूरत है।

1

स्ट्राउस्ट्रप "ऑटो_प्टर क्या है और वहां कोई ऑटो_एरे क्यों नहीं है" के सवाल पर चर्चा करता है और निष्कर्ष निकाला है कि वांछित कार्यक्षमता को वेक्टर के साथ पूरा करने के बाद बाद में कोई आवश्यकता नहीं है।

http://www.stroustrup.com/bs_faq2.html#auto_ptr

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