स्मार्ट पॉइंटर क्या है और मुझे कब इस्तेमाल करना चाहिए?


1818

स्मार्ट पॉइंटर क्या है और मुझे कब इस्तेमाल करना चाहिए?



2
ध्यान दें कि Visual Studio 2005 में std :: auto_ptr का कार्यान्वयन बुरी तरह से टूट गया है। <br> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98871 <br> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101842 का प्रयोग करें इसके बजाय लोगों को बढ़ावा दें।
रिचर्ड


1
यहाँ अलग-अलग फ्लेवर के स्मार्ट पॉइंटर्स बनाने की नटखट किरकिरी पर अलेक्जेंड्रेस्क्यू (फ्री) चैप्टर है: Informit.com/articles/article.aspx?p=31529 अपने कार्यान्वयन में, वह यह सुनिश्चित करने के लिए "नीतियों" के रूप में टेम्प्लेट तर्कों का उपयोग करता है कि वह कौन सी विशेषताएँ चाहता है ( उदाहरण के लिए, संदर्भ गिनती), जबकि मानक पुस्तकालय अलग-अलग कक्षाओं का उपयोग करता है। ध्यान दें कि वह stval :: unique_ptr संभव जैसा कुछ बनाने के लिए उपलब्ध संदर्भों से पहले भी लिख रहा था।
धातु

मैं उपरोक्त प्रश्न में एक और बिंदु जोड़ना चाहूंगा, स्मार्ट पॉइंटर std :: share_ptr में सबस्क्रिप्ट ऑपरेटर नहीं है और पॉंटर अंकगणित का समर्थन नहीं करता है, हम पॉइंटर में निर्मित प्राप्त करने के लिए () का उपयोग कर सकते हैं।
सुरेश एम।

जवाबों:


1883

अपडेट करें

यह उत्तर पुराना है, और इसलिए वर्णन करता है कि उस समय क्या 'अच्छा' था, जो बूस्ट लाइब्रेरी द्वारा प्रदान किए गए स्मार्ट पॉइंटर्स थे। C ++ 11 के बाद से, मानक पुस्तकालय ने पर्याप्त स्मार्ट पॉइंटर्स प्रकार प्रदान किए हैं, और इसलिए आपको इसके उपयोग का पक्ष लेना चाहिए std::unique_ptr, std::shared_ptrऔर std::weak_ptr

भी था std::auto_ptr। यह एक स्कोप्ड पॉइंटर की तरह बहुत अधिक था, सिवाय इसके कि इसमें "विशेष" खतरनाक नकल करने की क्षमता भी थी - जो अप्रत्याशित रूप से स्वामित्व को स्थानांतरित करता है।
इसे C ++ 11 में हटा दिया गया था और C ++ 17 में हटा दिया गया था , इसलिए आपको इसका उपयोग नहीं करना चाहिए।

std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership. 
                                 // p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.

पुराने ANSWER

एक स्मार्ट पॉइंटर एक ऐसा वर्ग है जो इंगित किए गए ऑब्जेक्ट के जीवनकाल को प्रबंधित करने के लिए एक 'रॉ' (या 'नंगे') C ++ पॉइंटर को लपेटता है। एक भी स्मार्ट पॉइंटर प्रकार नहीं है, लेकिन ये सभी एक कच्चे पॉइंटर को एक व्यावहारिक तरीके से अमूर्त करने की कोशिश करते हैं।

कच्चे पॉइंटर्स पर स्मार्ट पॉइंटर्स को प्राथमिकता दी जानी चाहिए। यदि आपको लगता है कि आपको पॉइंटर्स का उपयोग करने की आवश्यकता है (पहले विचार करें कि क्या आप वास्तव में करते हैं), तो आप सामान्य रूप से एक स्मार्ट पॉइंटर का उपयोग करना चाहते हैं क्योंकि यह कच्चे पॉइंटर्स के साथ कई समस्याओं को दूर कर सकता है, मुख्य रूप से ऑब्जेक्ट को हटाने और मेमोरी को लीक करना भूल सकता है।

कच्चे पॉइंटर्स के साथ, प्रोग्रामर को ऑब्जेक्ट को स्पष्ट रूप से तबाह करना पड़ता है जब वह उपयोगी नहीं होता है।

// Need to create the object to achieve some goal
MyObject* ptr = new MyObject(); 
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?

तुलना द्वारा एक स्मार्ट पॉइंटर एक नीति को परिभाषित करता है जब ऑब्जेक्ट नष्ट हो जाता है। आपको अभी भी ऑब्जेक्ट बनाना है, लेकिन अब आपको इसे नष्ट करने के बारे में चिंता करने की ज़रूरत नहीं है।

SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.

// Destruction of the object happens, depending 
// on the policy the smart pointer class uses.

// Destruction would happen even if DoSomething() 
// raises an exception

उपयोग में सबसे सरल नीति में स्मार्ट पॉइंटर रैपर ऑब्जेक्ट का दायरा शामिल होता है, जैसे कि इसके द्वारा कार्यान्वित boost::scoped_ptrया std::unique_ptr

void f()
{
    {
       std::unique_ptr<MyObject> ptr(new MyObject());
       ptr->DoSomethingUseful();
    } // ptr goes out of scope -- 
      // the MyObject is automatically destroyed.

    // ptr->Oops(); // Compile error: "ptr" not defined
                    // since it is no longer in scope.
}

ध्यान दें कि std::unique_ptrउदाहरणों की प्रतिलिपि नहीं बनाई जा सकती है। यह पॉइंटर को कई बार (गलत तरीके से) डिलीट होने से बचाता है। हालाँकि, आप अपने द्वारा कॉल किए जाने वाले अन्य कार्यों के लिए इसका संदर्भ दे सकते हैं।

std::unique_ptrs तब उपयोगी होते हैं जब आप ऑब्जेक्ट के जीवनकाल को कोड के किसी विशेष ब्लॉक में बाँधना चाहते हैं, या यदि आप इसे किसी अन्य ऑब्जेक्ट के अंदर सदस्य डेटा के रूप में एम्बेड करते हैं, तो उस अन्य ऑब्जेक्ट का जीवनकाल। ऑब्जेक्ट तब तक मौजूद रहता है जब तक कि कोड के ब्लॉक से बाहर नहीं निकल जाता है, या जब तक कि संबंधित ऑब्जेक्ट स्वयं नष्ट नहीं हो जाता है।

अधिक जटिल स्मार्ट पॉइंटर नीति में पॉइंटर की गिनती के संदर्भ शामिल होते हैं। यह पॉइंटर को कॉपी करने की अनुमति देता है। जब ऑब्जेक्ट के लिए अंतिम "संदर्भ" नष्ट हो जाता है, तो ऑब्जेक्ट हटा दिया जाता है। इस नीति के द्वारा कार्यान्वित किया जाता है boost::shared_ptrऔर std::shared_ptr

void f()
{
    typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
    MyObjectPtr p1; // Empty

    {
        MyObjectPtr p2(new MyObject());
        // There is now one "reference" to the created object
        p1 = p2; // Copy the pointer.
        // There are now two references to the object.
    } // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero. 
  // The object is deleted.

जब आपके ऑब्जेक्ट का जीवनकाल बहुत अधिक जटिल होता है, तो संदर्भ गिने पॉइंटर्स बहुत उपयोगी होते हैं, और कोड के किसी विशेष खंड या किसी अन्य ऑब्जेक्ट से सीधे बंधा नहीं होता है।

गिने हुए बिंदुओं को संदर्भित करने के लिए एक दोष है - झूलने वाले संदर्भ बनाने की संभावना:

// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!

एक अन्य संभावना परिपत्र संदर्भ बना रही है:

struct Owner {
   std::shared_ptr<Owner> other;
};

std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1

// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!

इस समस्या के आसपास काम करने के लिए, बूस्ट और सी ++ 11 ने ए weak_ptrको कमजोर (बेशुमार) संदर्भ को परिभाषित करने के लिए परिभाषित किया है shared_ptr


7
के std::auto_ptr<MyObject> p1 (new MyObject());बजाय आप का मतलब है std::auto_ptr<MyObject> p1 (new Owner());?
मतीन उल्हाक

35
बहुत बढ़िया जवाब। यह अच्छा होगा अगर इसे c ++ 11 के लिए अपडेट किया गया। मुझे यह उत्तर नए 11 मानक के बारे में जानकारी की तलाश में मिला और यह अच्छा होगा यदि भविष्य के आगंतुकों को अद्यतन जानकारी मिल सके। मुझे पता है कि auto_ptr को हटा दिया गया है। मेरा मानना ​​है कि वर्णित के रूप में shated_ptr और weak_ptr मौजूद हैं, और मुझे लगता है कि scoped_ptr अब मानक में unique_ptr है। यदि यह सत्य है, तो क्या यह उत्तर अद्यतन किया जा सकता है?
शाऊलबैक

16
यह कहना कि लटकते हुए संदर्भों को बनाने की संभावना गिना जाने वाले संदर्भों की एक खामी है, बिल्कुल पागल है। संभावित झूलने के संदर्भ किसी भी C ++ पॉइंटर का एक दोष हैं । वास्तव में, यह बिल्कुल सही है कि स्मार्ट पॉइंटर्स को कम करने का इरादा है ।
माइकल डोरस्ट

16
यदि आप एक स्मार्ट पॉइंटर को पॉइंटर घोषित करते हैं (जैसा कि उदाहरण में किया गया था) तो आप जानबूझकर स्मार्ट पॉइंटर के सभी लाभों को छोड़ देते हैं। यह एक खामी या एक डिजाइन दोष नहीं है, यह कल्पना का सबसे मूर्खतापूर्ण उपयोग है।
माइकल डोरस्ट

3
A const std::auto_ptrका उपयोग करना सुरक्षित है, यदि आप C ++ 03 के साथ फंस गए हैं। जब तक मुझे C ++ 11 तक पहुंच नहीं मिली, मैंने इसे pimpl पैटर्न के लिए बहुत उपयोग किया।
टोबी स्पाइट

302

यहां आधुनिक C ++ (C ++ 11 और बाद के दिनों) के इन दिनों के लिए एक सरल उत्तर दिया गया है:

  • स्मार्ट पॉइंटर क्या है?
    यह एक प्रकार है जिसका मान पॉइंटर्स की तरह उपयोग किया जा सकता है, लेकिन जो स्वचालित मेमोरी प्रबंधन की अतिरिक्त सुविधा प्रदान करता है: जब एक स्मार्ट पॉइंटर अब उपयोग में नहीं होता है, तो यह जिस मेमोरी को इंगित करता है वह डीलक्लोकेटेड है ( विकिपीडिया पर अधिक विस्तृत परिभाषा भी देखें )।
  • मुझे कब उपयोग करना चाहिए?
    कोड में जिसमें मेमोरी के टुकड़े के स्वामित्व को ट्रैक करना, आवंटन या डी-आवंटन करना शामिल है; स्मार्ट पॉइंटर अक्सर आपको इन चीजों को स्पष्ट रूप से करने की आवश्यकता को बचाता है।
  • लेकिन मुझे किन स्मार्ट पॉइंटर का इस्तेमाल करना चाहिए?
    • std::unique_ptrजब आप एक ही ऑब्जेक्ट पर कई संदर्भ रखने का इरादा नहीं करते हैं तो उपयोग करें । उदाहरण के लिए, इसे एक पॉइंटर के लिए मेमोरी में उपयोग करें जो कुछ दायरे में प्रवेश करने पर आवंटित हो जाता है और दायरे से बाहर निकलने पर डी-आवंटित किया जाता है।
    • std::shared_ptrजब आप अपनी वस्तु को कई स्थानों से संदर्भित करना चाहते हैं, तब उपयोग करें - और यह नहीं चाहते कि आपकी वस्तु को तब तक आबंटित किया जाए जब तक कि ये सभी संदर्भ स्वयं नहीं हो जाते।
    • std::weak_ptrजब आप अपनी वस्तु को कई स्थानों से संदर्भित करना चाहते हैं, तो उपयोग करें - उन संदर्भों के लिए जिनके लिए इसे अनदेखा करना और डील-डौल करना ठीक है (इसलिए वे ध्यान दें कि जब आप किसी वस्तु को हटाने की कोशिश करते हैं तो वस्तु चली गई)
    • boost::स्मार्ट पॉइंटर का उपयोग न करें या std::auto_ptrविशेष मामलों को छोड़कर जो आप पढ़ सकते हैं यदि आप अवश्य करें।
  • अरे, मैंने नहीं पूछा कि कौन सा उपयोग करना है!
    आह, लेकिन आप वास्तव में इसे स्वीकार करना चाहते थे।
  • तो मुझे नियमित पॉइंटर्स का उपयोग कब करना चाहिए?
    ज्यादातर कोड में जो स्मृति स्वामित्व से बेखबर है। यह आम तौर पर उन कार्यों में होता है जो किसी और जगह से एक पॉइंटर प्राप्त करते हैं और न तो आवंटित करते हैं और न ही डी-आवंटित करते हैं, और पॉइंटर की एक प्रति संग्रहीत नहीं करते हैं जो उनके निष्पादन को रेखांकित करता है।

5
यह ध्यान देने योग्य है कि जबकि स्मार्ट (मालिक) पॉइंटर्स उचित मेमोरी प्रबंधन के साथ मदद करते हैं, कच्चे (गैर-मालिक) पॉइंटर्स अभी भी डेटा संरचनाओं में अन्य संगठनात्मक उद्देश्यों के लिए उपयोगी हैं। हर्ब सटर ने CppCon 2016 में इस मामले पर एक शानदार प्रस्तुति दी, जिसे आप YouTube पर देख सकते हैं: C ++ में Leak-Freedom ... बाय डिफॉल्ट।
wiktor.wandachowicz

1
@ wiktor.wandachowicz T*को std::unique_ptr<T>क्या std::weak_ptr<T>करना हैstd::shared_ptr<T>
Caleth

@ कैलेथ: नहीं, मैं ऐसा नहीं कहूंगा।
ईनपोकलुम

1
@TonyTannous: सम्मान के साथ - यह एक प्रमुख संपादन था; और मुझे अपना जवाब महसूस नहीं हुआ, जो कि सार है, इसकी जरूरत है। मेरा सुझाव है कि आप उदाहरण को एक टिप्पणी में लिंक पर एक अलग उत्तर दें।
ईनपोक्लुम

112

स्मार्ट पॉइंटर कुछ अतिरिक्त कार्यक्षमता के साथ एक पॉइंटर-प्रकार का प्रकार है, जैसे स्वचालित मेमोरी डीलक्लेशन, संदर्भ गिनती आदि।

छोटा इंट्रो पेज स्मार्ट पॉइंटर्स पर उपलब्ध है - क्या, क्यों, कौन सा?

सरल स्मार्ट-पॉइंटर प्रकारों में से एक है std::auto_ptr(C ++ मानक का अध्याय 20.4.5), जो जब स्कोप से बाहर होता है तो मेमोरी को स्वचालित रूप से डीलकोलेट करने की अनुमति देता है और अपवादों को फेंकने पर यह साधारण पॉइंटर उपयोग से अधिक मजबूत होता है, हालांकि कम लचीला।

एक और सुविधाजनक प्रकार है, boost::shared_ptrजो संदर्भ की गिनती को लागू करता है और जब ऑब्जेक्ट का कोई संदर्भ नहीं रहता है तो स्वचालित रूप से मेमोरी को हटा देता है। यह मेमोरी लीक से बचने में मदद करता है और RAII को लागू करने के लिए उपयोग करना आसान है ।

डेविड वन्देवोर्डे, निकोलई एम। जोसुटिस , अध्याय 20 अध्याय द्वारा पुस्तक "सी ++ टेम्प्लेट्स: द कम्प्लीट गाइड" में विषय को गहराई से कवर किया गया है । स्मार्ट पॉइंटर्स कुछ विषयों को शामिल किया गया:

  • अपवादों के खिलाफ सुरक्षा
  • धारकों, (ध्यान दें, std :: auto_ptr इस प्रकार के स्मार्ट पॉइंटर का कार्यान्वयन है)
  • संसाधन अधिग्रहण प्रारंभिक है (इसका उपयोग अक्सर C ++ में अपवाद-सुरक्षित संसाधन प्रबंधन के लिए किया जाता है)
  • धारक की सीमाएँ
  • संदर्भ की गिनती
  • समवर्ती काउंटर पहुंच
  • विनाश और निपटारा

2
चेतावनी std::auto_ptrको हटा दिया जाता है और अत्यधिक हतोत्साहित किया जाता है क्योंकि आप गलती से स्वामित्व स्थानांतरित कर सकते हैं। : - सी ++ 11 बूस्ट, उपयोग की जरूरत को हटा std::unique_ptr, std::shared_ptrऔरstd::weak_ptr
ninMonkey

42

क्रिस, सर्गदेव और लिलीओड द्वारा प्रदान की गई परिभाषाएं सही हैं। मैं एक सरल परिभाषा को पसंद करता हूं, बस अपने जीवन को सरल रखने के लिए: एक स्मार्ट पॉइंटर बस एक ऐसा वर्ग है जो ओवररेट -> और *ऑपरेटरों को अधिभारित करता है । जिसका अर्थ है कि आपकी वस्तु शब्दार्थ सूचक की तरह दिखती है, लेकिन आप इसे ठंडी चीजें कर सकते हैं, जिसमें संदर्भ गिनती, स्वचालित विनाश आदि शामिल हैं shared_ptrऔर auto_ptrज्यादातर मामलों में पर्याप्त हैं, लेकिन छोटे आइडियोसिंक्राइसिस के अपने स्वयं के सेट के साथ आते हैं।


30

एक स्मार्ट पॉइंटर एक रेगुलर (टाइप किया हुआ) पॉइंटर की तरह होता है, जैसे "चार *", सिवाय इसके कि जब पॉइंटर खुद ही स्कोप से बाहर चला जाता है तो यह किस पॉइंट को डिलीट कर देता है। आप इसका उपयोग कर सकते हैं जैसे कि आप "->" का उपयोग करके एक नियमित पॉइंटर करेंगे, लेकिन यदि आपको डेटा के लिए वास्तविक पॉइंटर की आवश्यकता नहीं है। उसके लिए, आप "& * ptr" का उपयोग कर सकते हैं।

यह इसके लिए उपयोगी है:

  • जिन वस्तुओं को नए के साथ आवंटित किया जाना चाहिए, लेकिन आप उस स्टैक पर कुछ के रूप में एक ही जीवनकाल करना चाहेंगे। यदि ऑब्जेक्ट एक स्मार्ट पॉइंटर को सौंपा गया है, तो प्रोग्राम को उस फ़ंक्शन / ब्लॉक से बाहर निकालने पर उन्हें हटा दिया जाएगा।

  • कक्षाओं के डेटा सदस्य, ताकि जब ऑब्जेक्ट को हटा दिया जाए तो सभी स्वामित्व डेटा नष्ट कर दिया जाए, बिना विध्वंसक में कोई विशेष कोड (आपको यह सुनिश्चित करने की आवश्यकता होगी कि विध्वंसक आभासी है, जो लगभग हमेशा एक अच्छी बात है) ।

जब आप एक स्मार्ट पॉइंटर का उपयोग नहीं करना चाहेंगे:

  • ... सूचक को वास्तव में डेटा का स्वामी नहीं होना चाहिए ... यानी, जब आप डेटा का उपयोग कर रहे हैं, लेकिन आप इसे उस फ़ंक्शन से बचना चाहते हैं जहां आप इसे संदर्भित कर रहे हैं।
  • ... स्मार्ट पॉइंटर कुछ बिंदु पर नष्ट होने वाला नहीं है। आप इसे स्मृति में नहीं बैठना चाहते हैं जो कभी भी नष्ट न हो (जैसे कि एक वस्तु जो गतिशील रूप से आवंटित की गई है लेकिन स्पष्ट रूप से नष्ट नहीं की जाएगी)।
  • ... दो स्मार्ट पॉइंटर्स एक ही डेटा को इंगित कर सकते हैं। (हालांकि, यहां तक ​​कि चालाक बिंदु भी हैं जो संभाल लेंगे ... जिसे संदर्भ गिनती कहा जाता है ।)

यह सभी देखें:


18

अधिकांश प्रकार के स्मार्ट पॉइंटर्स आपके लिए पॉइंटर-टू ऑब्जेक्ट का निपटान करते हैं। यह बहुत आसान है क्योंकि आपको मैन्युअल रूप से अब और वस्तुओं के निपटान के बारे में सोचने की ज़रूरत नहीं है।

सबसे अधिक इस्तेमाल किया जाने वाला स्मार्ट पॉइंटर्स हैं std::tr1::shared_ptr(या boost::shared_ptr), और, कम सामान्यतः std::auto_ptr। मैं नियमित रूप से उपयोग की सलाह देता हूं shared_ptr

shared_ptrबहुत बहुमुखी है और कई प्रकार के निपटान परिदृश्यों से संबंधित है, जिनमें ऐसे मामले शामिल हैं जिनमें वस्तुओं को "डीएलएल सीमाओं के पार जाना" चाहिए (यदि libcआपके कोड और डीएलएल के बीच अलग-अलग एस का उपयोग किया जाता है तो सामान्य दुःस्वप्न मामला )।


18

एक स्मार्ट पॉइंटर एक ऐसी वस्तु है जो एक पॉइंटर की तरह काम करता है, लेकिन इसके अतिरिक्त निर्माण, विनाश, प्रतिलिपि बनाने, हिलाने और डिफरेंसिंग पर नियंत्रण प्रदान करता है।

कोई अपने स्मार्ट पॉइंटर को लागू कर सकता है, लेकिन कई लाइब्रेरी अलग-अलग फायदे और कमियों के साथ स्मार्ट पॉइंटर कार्यान्वयन भी प्रदान करते हैं।

उदाहरण के लिए, बूस्ट निम्नलिखित स्मार्ट सूचक कार्यान्वयन प्रदान करता है:

  • shared_ptr<T>यह Tनिर्धारित करने के लिए एक संदर्भ गिनती का उपयोग करने के लिए एक संकेतक है जब ऑब्जेक्ट की अब आवश्यकता नहीं है।
  • scoped_ptr<T>जब यह कार्यक्षेत्र से बाहर चला जाता है तो एक सूचक स्वचालित रूप से हटा दिया जाता है। कोई असाइनमेंट संभव नहीं है।
  • intrusive_ptr<T>एक और संदर्भ गिनती सूचक है। यह तुलना में बेहतर प्रदर्शन प्रदान करता है shared_ptr, लेकिन Tइसके लिए अपने स्वयं के संदर्भ गिनती तंत्र प्रदान करने के प्रकार की आवश्यकता होती है।
  • weak_ptr<T>एक कमजोर सूचक है, जो shared_ptrपरिपत्र संदर्भों से बचने के लिए काम करता है ।
  • shared_array<T>की तरह है shared_ptr, लेकिन सरणियों के लिए T
  • scoped_array<T>की तरह है scoped_ptr, लेकिन सरणियों के लिए T

ये प्रत्येक के केवल एक रैखिक विवरण हैं और आवश्यकता के अनुसार उपयोग किए जा सकते हैं, आगे के विवरण और उदाहरणों के लिए बूस्ट के प्रलेखन को देख सकते हैं।

इसके अतिरिक्त, C ++ मानक पुस्तकालय तीन स्मार्ट पॉइंटर्स प्रदान करता है; साझा स्वामित्व के लिए std::unique_ptr, अद्वितीय स्वामित्व के std::shared_ptrलिए और std::weak_ptrstd::auto_ptrC ++ 03 में मौजूद है लेकिन अब पदावनत हो गया है।


कृपया समझाएं कि scoped_ptrस्थानीय रूप से घोषित क्यों नहीं है const unique_ptr- जो कि दायरे से बाहर निकलने पर भी नष्ट हो जाता है।
ईनपोकलुम

11

इसी तरह के उत्तरों के लिए लिंक यहां दिया गया है: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

एक स्मार्ट पॉइंटर एक ऐसी वस्तु है जो सामान्य पॉइंटर की तरह काम करता है, दिखता है और महसूस करता है लेकिन अधिक कार्यक्षमता प्रदान करता है। C ++ में, स्मार्ट पॉइंटर्स को टेम्पलेट कक्षाओं के रूप में लागू किया जाता है जो एक पॉइंटर को एनकैप्सुलेट करता है और मानक पॉइंटर ऑपरेटरों को ओवरराइड करता है। वे नियमित संकेत पर कई फायदे हैं। उन्हें शून्य बिंदु या संकेत के रूप में आरंभ करने की गारंटी दी जाती है। एक अशक्त सूचक के माध्यम से अप्रत्यक्षता की जाँच की जाती है। कोई डिलीट कभी जरूरी नहीं है। जब अंतिम पॉइंटर उनके पास चला गया है तो ऑब्जेक्ट स्वचालित रूप से मुक्त हो जाते हैं। इन स्मार्ट पॉइंटर्स के साथ एक महत्वपूर्ण समस्या यह है कि नियमित पॉइंटर्स के विपरीत, वे इनहेरिटेंस का सम्मान नहीं करते हैं। स्मार्ट पॉइमर पॉलीमॉर्फिक कोड के लिए अनाकर्षक हैं। नीचे दिए गए स्मार्ट पॉइंटर्स के कार्यान्वयन के लिए एक उदाहरण है।

उदाहरण:

template <class X>
class smart_pointer
{
          public:
               smart_pointer();                          // makes a null pointer
               smart_pointer(const X& x)            // makes pointer to copy of x

               X& operator *( );
               const X& operator*( ) const;
               X* operator->() const;

               smart_pointer(const smart_pointer <X> &);
               const smart_pointer <X> & operator =(const smart_pointer<X>&);
               ~smart_pointer();
          private:
               //...
};

यह वर्ग एक स्मार्ट पॉइंटर को X के ऑब्जेक्ट पर लागू करता है। ऑब्जेक्ट ही हीप पर स्थित है। यहाँ इसका उपयोग कैसे किया जाता है:

smart_pointer <employee> p= employee("Harris",1333);

अन्य ओवरलोड ऑपरेटरों की तरह, पी एक नियमित सूचक की तरह व्यवहार करेगा,

cout<<*p;
p->raise_salary(0.5);

9

http://en.wikipedia.org/wiki/Smart_pointer

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


6

बता दें कि T इस ट्यूटोरियल में C ++ में एक क्लास है, इसे 3 प्रकारों में विभाजित किया जा सकता है:

1) कच्चे संकेत :

T a;  
T * _ptr = &a; 

वे एक मेमोरी एड्रेस को मेमोरी में किसी लोकेशन पर रखते हैं। सावधानी बरतें, क्योंकि ट्रैक को बनाए रखने के लिए कार्यक्रम कठिन हो जाते हैं।

कास्ट डेटा या पते के साथ संकेत {आगे पीछे पढ़ें}

T a ; 
const T * ptr1 = &a ; 
T const * ptr1 = &a ;

एक डेटा टाइप T की ओर इशारा करता है जो एक कास्ट है। मतलब आप पॉइंटर का उपयोग करके डेटा प्रकार नहीं बदल सकते। यानी *ptr1 = 19; काम नहीं करेगा। लेकिन आप पॉइंटर को मूव कर सकते हैं। यानी ptr1++ , ptr1--; आदि काम करेंगे। पीछे की ओर पढ़ें: T टाइप करने के लिए पॉइंटर जो कांस्टेबल है

  T * const ptr2 ;

डेटा टाइप T के लिए एक कास्ट पॉइंटर। मतलब आप पॉइंटर को हिला नहीं सकते लेकिन आप पॉइंटर द्वारा बताए गए मान को बदल सकते हैं। यानी *ptr2 = 19काम करेगा लेकिन ptr2++ ; ptr2--आदि नहीं चलेगा। पीछे की ओर पढ़ें: एक प्रकार टी के लिए कास्ट पॉइंटर

const T * const ptr3 ; 

एक कास्ट पॉइंटर को एक कास्ट डेटा टाइप T। मतलब आप न तो पॉइंटर को हिला सकते हैं और न ही आप प्वाइंटर को डेटा टाइप पॉइंटर बदल सकते हैं। अर्थात । ptr3-- ; ptr3++ ; *ptr3 = 19;काम नहीं करेगा

3) स्मार्ट पॉइंटर्स : { #include <memory>}

साझा सूचक :

  T a ; 
     //shared_ptr<T> shptr(new T) ; not recommended but works 
     shared_ptr<T> shptr = make_shared<T>(); // faster + exception safe

     std::cout << shptr.use_count() ; // 1 //  gives the number of " 
things " pointing to it. 
     T * temp = shptr.get(); // gives a pointer to object

     // shared_pointer used like a regular pointer to call member functions
      shptr->memFn();
     (*shptr).memFn(); 

    //
     shptr.reset() ; // frees the object pointed to be the ptr 
     shptr = nullptr ; // frees the object 
     shptr = make_shared<T>() ; // frees the original object and points to new object

पॉइंटर द्वारा बताई गई वस्तु को कितनी "चीजों" को इंगित करने के लिए संदर्भ गिनती का उपयोग करके कार्यान्वित किया गया। जब यह संख्या 0 पर जाती है, तो ऑब्जेक्ट स्वचालित रूप से हटा दिया जाता है, अर्थात ऑब्जेक्ट को हटा दिया जाता है जब ऑब्जेक्ट के लिए सभी शेयर_पार्ट इंगित करते हैं, तो यह गुंजाइश से बाहर हो जाता है। यह उन वस्तुओं को हटाने के सिरदर्द से छुटकारा दिलाता है जिन्हें आपने नए का उपयोग करके आवंटित किया है।

कमजोर सूचक: साझा सूचक का उपयोग करते समय उत्पन्न होने वाले चक्रीय संदर्भ से निपटने में मदद करता है। यदि आपके पास दो साझा बिंदुओं द्वारा इंगित दो ऑब्जेक्ट हैं और एक आंतरिक साझा सूचक है जो एक दूसरे को साझा किए गए सूचक की ओर इशारा करता है तो एक चक्रीय संदर्भ होगा और ऑब्जेक्ट नहीं होगा साझा किए गए बिंदुओं के दायरे से बाहर जाने पर हटा दिया जाए। इसे हल करने के लिए, आंतरिक सदस्य को एक साझा_पत्र से कमजोर_प्रति में बदलें। नोट: एक कमजोर पॉइंटर उपयोग लॉक () द्वारा इंगित तत्व तक पहुंचने के लिए, यह एक कमजोर_प्रति देता है।

T a ; 
shared_ptr<T> shr = make_shared<T>() ; 
weak_ptr<T> wk = shr ; // initialize a weak_ptr from a shared_ptr 
wk.lock()->memFn() ; // use lock to get a shared_ptr 
//   ^^^ Can lead to exception if the shared ptr has gone out of scope
if(!wk.expired()) wk.lock()->memFn() ;
// Check if shared ptr has gone out of scope before access

देखें: कब है std :: weak_ptr उपयोगी?

अद्वितीय सूचक: विशेष स्वामित्व के साथ हल्के वजन वाले स्मार्ट पॉइंटर। जब पॉइंटर्स के बीच ऑब्जेक्ट्स को साझा किए बिना पॉइंटर पॉइंट्स को यूनीक ऑब्जेक्ट्स के लिए उपयोग करें।

unique_ptr<T> uptr(new T);
uptr->memFn(); 

//T * ptr = uptr.release(); // uptr becomes null and object is pointed to by ptr
uptr.reset() ; // deletes the object pointed to by uptr 

अद्वितीय ptr द्वारा बताई गई वस्तु को बदलने के लिए, चाल शब्दार्थ का उपयोग करें

unique_ptr<T> uptr1(new T);
unique_ptr<T> uptr2(new T);
uptr2 = std::move(uptr1); 
// object pointed by uptr2 is deleted and 
// object pointed by uptr1 is pointed to by uptr2
// uptr1 becomes null 

संदर्भ: वे मूल रूप से कॉन्स्टेबल के रूप में हो सकते हैं, अर्थात एक पॉइंटर जो कि कास्ट है और बेहतर सिंटैक्स के साथ नहीं ले जाया जा सकता है।

देखें: C ++ में पॉइंटर वेरिएबल और रेफरेंस वेरिएबल के बीच क्या अंतर हैं?

r-value reference : reference to a temporary object   
l-value reference : reference to an object whose address can be obtained
const reference : reference to a data type which is const and cannot be modified 

संदर्भ: https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ इस प्रश्न को इंगित करने के लिए आंद्रे का धन्यवाद।


3

एक स्मार्ट पॉइंटर एक क्लास है, एक सामान्य पॉइंटर का आवरण है। सामान्य बिंदुओं के विपरीत, स्मार्ट पॉइंट का जीवन चक्र एक संदर्भ गणना (स्मार्ट पॉइंटर ऑब्जेक्ट को कितनी बार असाइन किया गया है) पर आधारित है। इसलिए जब भी एक स्मार्ट पॉइंटर दूसरे को सौंपा जाता है, तो आंतरिक संदर्भ गणना प्लस प्लस। और जब भी वस्तु दायरे से बाहर जाती है, तो संदर्भ शून्य से नीचे की गणना करता है।

स्वचालित पॉइंटर, हालांकि समान दिखता है, स्मार्ट पॉइंटर से पूरी तरह से अलग है। यह एक सुविधाजनक वर्ग है जो संसाधन से निपटता है जब भी कोई स्वचालित पॉइंटर ऑब्जेक्ट चर दायरे से बाहर जाता है। कुछ हद तक, यह एक पॉइंटर बनाता है (गतिशील रूप से आवंटित मेमोरी के लिए) स्टैक चर के समान काम करता है (संकलित समय में सांख्यिकीय रूप से आवंटित)।


2

स्मार्ट पॉइंटर्स वे हैं जहाँ आपको मेमोरी डी-एलोकेशन, रिसोर्स शेयरिंग और ट्रांसफर के बारे में चिंता करने की ज़रूरत नहीं है।

आप इन पॉइंटर का उपयोग ठीक उसी तरह से कर सकते हैं जिस तरह जावा में कोई आवंटन कार्य करता है। जावा गारबेज कलेक्टर में चाल करता है, जबकि स्मार्ट पॉइंटर्स में चाल विध्वंसक द्वारा किया जाता है।


1

मौजूदा उत्तर अच्छे हैं, लेकिन उस समस्या को कवर न करें जब कोई स्मार्ट पॉइंटर आपके द्वारा हल करने की कोशिश की जा रही समस्या का पूर्ण (पूर्ण) उत्तर न हो।

स्मार्ट पॉइंटर का उपयोग करके अन्य चीजों में (अच्छी तरह से समझाया गया) एक संभव समाधान है कि हम एक एब्सट्रैक्ट क्लास को फ़ंक्शन प्रकार के रूप में कैसे उपयोग करते हैं? जिसे इस प्रश्न के डुप्लिकेट के रूप में चिह्नित किया गया है। हालाँकि, यह पूछने का पहला प्रश्न कि क्या C ++ में रिटर्न टाइप के रूप में एक अमूर्त (या वास्तव में, कोई) आधार वर्ग निर्दिष्ट करने का प्रलोभन दिया गया है, "आप वास्तव में क्या मतलब है?"। बढ़ावा देने वाले पॉइंटर कंटेनर लाइब्रेरी के दस्तावेज़ीकरण में C ++ (और यह अन्य भाषाओं के लिए कैसे अलग है) में मुहावरेदार वस्तु उन्मुख प्रोग्रामिंग की एक अच्छी चर्चा (आगे के संदर्भों के साथ) है। सारांश में, C ++ में आपको स्वामित्व के बारे में सोचना होगा। कौन से स्मार्ट पॉइंटर्स आपकी मदद करते हैं, लेकिन एकमात्र समाधान नहीं है, या हमेशा एक पूर्ण समाधान (वे आपको बहुरूपिक प्रतिलिपि नहीं देते हैं) और हमेशा एक समाधान नहीं है जिसे आप अपने इंटरफ़ेस में उजागर करना चाहते हैं (और फ़ंक्शन रिटर्न एक भयानक लगता है एक अंतरफलक की तरह)। उदाहरण के लिए, किसी संदर्भ को लौटाना पर्याप्त हो सकता है। लेकिन इन मामलों में (स्मार्ट सूचक, सूचक कंटेनर या बस एक संदर्भ लौटने) के सभी में आप एक से वापसी को बदल दिया है मूल्य के कुछ फार्म के लिए संदर्भ । यदि आपको वास्तव में प्रतिलिपि की आवश्यकता है तो आपको अधिक बायलरप्लेट "मुहावरा" जोड़ने की आवश्यकता हो सकती है या मुहावरेदार से परे जा सकते हैं (या अन्यथा) सी ++ में ओओपी अधिक एडोब पॉली या Boost.TypeEypeureure जैसे पुस्तकालयों का उपयोग करते हुए अधिक सामान्य बहुरूपता के लिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.