यहां से अपनाया गया ।
C ++ मानक लाइब्रेरी में अधिकांश टेम्प्लेट की आवश्यकता होती है कि उन्हें पूर्ण प्रकारों के साथ त्वरित किया जाए। हालांकि shared_ptr
और unique_ptr
कर रहे हैं आंशिक अपवाद नहीं। कुछ, लेकिन उनके सभी सदस्यों को अपूर्ण प्रकारों से त्वरित नहीं किया जा सकता है। इसके लिए प्रेरणा स्मार्ट पॉइंटर्स का उपयोग करके pimpl जैसे मुहावरों का समर्थन करना है , और अपरिभाषित व्यवहार को जोखिम में डाले बिना।
अधूरा व्यवहार तब हो सकता है जब आपके पास एक अपूर्ण प्रकार होता है और आप delete
उस पर कॉल करते हैं:
class A;
A* a = ...;
delete a;
ऊपर कानूनी कोड है। यह संकलन करेगा। आपका कंपाइलर उपरोक्त कोड के लिए चेतावनी का अनुकरण कर सकता है या नहीं कर सकता है। जब यह निष्पादित होता है, तो बुरी चीजें हो जाएंगी। यदि आप बहुत भाग्यशाली हैं तो आपका प्रोग्राम क्रैश हो जाएगा। हालाँकि एक अधिक संभावित परिणाम यह है कि आपका प्रोग्राम चुपचाप मेमोरी को लीक कर ~A()
देगा क्योंकि इसे नहीं बुलाया जाएगा।
auto_ptr<A>
उपरोक्त उदाहरण का उपयोग करने से मदद नहीं मिलती है। आपको अभी भी वही अपरिभाषित व्यवहार मिलता है जैसे कि आपने कच्चे पॉइंटर का इस्तेमाल किया हो।
फिर भी, कुछ स्थानों पर अपूर्ण कक्षाओं का उपयोग करना बहुत उपयोगी है! यह वह जगह है जहाँ shared_ptr
और unique_ptr
मदद करते हैं। इन स्मार्ट पॉइंटर्स में से एक का उपयोग आपको एक अपूर्ण प्रकार के साथ दूर जाने देगा, सिवाय इसके कि जहां एक पूर्ण प्रकार होना आवश्यक है। और सबसे महत्वपूर्ण बात, जब एक पूर्ण प्रकार का होना आवश्यक है, तो आप एक कंपाइल-टाइम त्रुटि प्राप्त करते हैं यदि आप उस बिंदु पर अपूर्ण प्रकार के साथ स्मार्ट पॉइंटर का उपयोग करने का प्रयास करते हैं।
अधिक अपरिभाषित व्यवहार नहीं:
यदि आपका कोड संकलित करता है, तो आपको हर जगह एक पूर्ण प्रकार का उपयोग करना होगा जो आपको चाहिए।
class A
{
class impl;
std::unique_ptr<impl> ptr_; // ok!
public:
A();
~A();
// ...
};
shared_ptr
और unique_ptr
विभिन्न स्थानों में एक पूर्ण प्रकार की आवश्यकता होती है। कारण अस्पष्ट हैं, एक गतिशील डेलेटर बनाम एक स्थिर डेलेटर के साथ क्या करना है। सटीक कारण महत्वपूर्ण नहीं हैं। वास्तव में, अधिकांश कोड में आपके लिए वास्तव में यह जानना महत्वपूर्ण नहीं है कि एक पूर्ण प्रकार की आवश्यकता कहां है। बस कोड, और यदि आप इसे गलत पाते हैं, तो संकलक आपको बताएगा।
हालाँकि, अगर यह आपके लिए मददगार है, तो यहाँ एक तालिका है जो संपूर्णता आवश्यकताओं के संबंध में shared_ptr
और उसके कई सदस्यों के दस्तावेज प्रस्तुत unique_ptr
करती है। यदि सदस्य को पूर्ण प्रकार की आवश्यकता होती है, तो प्रविष्टि में "सी" है, अन्यथा तालिका प्रविष्टि "आई" से भरी गई है।
Complete type requirements for unique_ptr and shared_ptr
unique_ptr shared_ptr
+------------------------+---------------+---------------+
| P() | I | I |
| default constructor | | |
+------------------------+---------------+---------------+
| P(const P&) | N/A | I |
| copy constructor | | |
+------------------------+---------------+---------------+
| P(P&&) | I | I |
| move constructor | | |
+------------------------+---------------+---------------+
| ~P() | C | I |
| destructor | | |
+------------------------+---------------+---------------+
| P(A*) | I | C |
+------------------------+---------------+---------------+
| operator=(const P&) | N/A | I |
| copy assignment | | |
+------------------------+---------------+---------------+
| operator=(P&&) | C | I |
| move assignment | | |
+------------------------+---------------+---------------+
| reset() | C | I |
+------------------------+---------------+---------------+
| reset(A*) | C | C |
+------------------------+---------------+---------------+
पॉइंटर रूपांतरणों की आवश्यकता वाले किसी भी संचालन के लिए unique_ptr
और दोनों के लिए पूर्ण प्रकार की आवश्यकता होती है shared_ptr
।
unique_ptr<A>{A*}
निर्माता एक साथ प्राप्त कर सकते हैं अधूरा A
ही संकलक के लिए एक कॉल स्थापित करने के लिए आवश्यक नहीं है यदि ~unique_ptr<A>()
। उदाहरण के लिए यदि आप unique_ptr
ढेर लगाते हैं, तो आप एक अपूर्ण के साथ भाग सकते हैं A
। इस बिंदु पर अधिक जानकारी यहाँ बैरीTheHatchet के उत्तर में पाई जा सकती है ।
shared_ptr
/unique_ptr
" अंत में तालिका को आपके प्रश्न का उत्तर देना चाहिए।