2009-03-18 16 views
16

कुछ ट्यूटोरियल पढ़ने के बाद मैं इस निष्कर्ष पर आया कि किसी को वस्तुओं के लिए हमेशा पॉइंटर्स का उपयोग करना चाहिए। लेकिन कुछ QT ट्यूटोरियल (http://zetcode.com/gui/qt4/painting/) पढ़ने के दौरान मैंने कुछ अपवाद भी देखे हैं जहां स्टैक पर QPaint ऑब्जेक्ट बनाया गया है। तो अब मैं उलझन में हूँ। मुझे पॉइंटर्स का उपयोग कब करना चाहिए?सी ++: पॉइंटर्स का उपयोग कब करें?

+0

क्यूटी ट्यूटोरियल स्टैक पर क्यूपेंट ऑब्जेक्ट बनाते हैं क्योंकि क्यूपेंट ऑब्जेक्ट का उपयोगी जीवन संकलन समय पर जाना जाता है और यह वास्तव में {} की मिलान की गई जोड़ी से घिरा हुआ है। –

+0

क्यूपेन, क्यूपेन्टर और क्यूप्लिकेशन के लिए भी यही है। –

+0

पॉइंटर के बारे में जानना बहुत अच्छा है कि अब सी ++ में पॉइंटर्स के कुछ सुरक्षित कार्यान्वयन जैसे अद्वितीय_ptr या weak_ptr हैं, जब आपको पॉइंटर का उपयोग करने की आवश्यकता होती है, तो आपको उन्हें उपयोग करने की आवश्यकता होती है (निम्न स्तर कोड पर कुछ दुर्लभ अपवाद के साथ) – MokaT

उत्तर

41

अगर तुम नहीं जानते कि जब तुम संकेत का उपयोग करना चाहिए सिर्फ उन्हें प्रयोग नहीं करते।

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

+6

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

+0

@ एआर। उम्मीद है कि मैंने jamolkhon को हमेशा पॉइंटर्स का उपयोग न करने के लिए सीखने दिया - उसके प्रश्न के पहले वाक्य को देखें। मैंने उस संदर्भ को केवल शीर्षक में ही नहीं लिया। इसके अलावा, अन्य प्रश्न कुछ उपयोगों की सूची देते हैं। – CiscoIPPhone

+0

मैंने आखिरी वाक्य को ध्यान में रखा, आप जानते हैं, प्रश्न भाग। –

4

वे कौन से ट्यूटोरियल होंगे? असल में, नियम यह है कि आपको केवल पॉइंटर्स का उपयोग करना चाहिए जब आपको बिल्कुल करना होगा, जो कि शायद ही कभी है। आपको कोएनिग & म्यू द्वारा Accelerated C++ जैसे सी ++ पर एक अच्छी किताब पढ़ने की आवश्यकता है।

संपादित करें: थोड़ा स्पष्ट करने के लिए - दो उदाहरणों जहां एक सूचक का उपयोग नहीं हैं (स्ट्रिंग एक नमूना के रूप में यहां इस्तेमाल किया जा रहा है - एक ही किसी भी अन्य प्रकार के लिए जाना होगा):

class Person { 
    public: 
     string name;  // NOT string * name; 
    ... 
}; 


void f() { 
    string value;  // NOT string * value 
    // use vvalue 
} 
+0

कैसे ढेर की सीमाएं? – Jamol

+0

वह सीमा क्या होगी? –

+0

अच्छी तरह से मेरा मतलब कुछ सिस्टमों पर है यदि स्टैक के सभी आकार सीमित नहीं हैं? – Jamol

21

संकेत का उपयोग कर के लिए मुख्य कारण हैं:

  1. नियंत्रण वस्तु जीवन;
  2. संदर्भों का उपयोग नहीं कर सकता (उदा। आप वेक्टर में कुछ गैर-प्रतिलिपि बनाना चाहते हैं);
  3. आपको किसी तीसरे पक्ष के फ़ंक्शन में पॉइंटर पास करना चाहिए;
  4. शायद कुछ अनुकूलन कारण हैं, लेकिन मुझे यकीन नहीं है।
+4

मुझे लगता है कि पॉइंटर्स का सबसे महत्वपूर्ण बिंदु ऑब्जेक्ट्स के जीवनकाल को नियंत्रित कर रहा है –

+0

प्वाइंट # 2 विशेष रूप से क्यूटी पर लागू होता है क्योंकि अधिकांश क्यूटी ग्राफिक्स से संबंधित ऑब्जेक्ट कॉपी करने योग्य नहीं होते हैं। –

+0

@caparcode, वास्तव में, QObjects कॉपी करने योग्य नहीं हैं। इसमें जीयूआई तत्व और बहुत कम ग्राफिक कक्षाएं, और कुछ अन्य सामान शामिल हैं। अन्य वर्ग भी किसी भी कारण से गैर-प्रतिलिपि हो सकते हैं। – strager

1

आम तौर पर वस्तुओं के लिए संकेत/संदर्भ का उपयोग करते हैं:

  • (मुझे यकीन है कि क्या सामान्य ढेर आकार है नहीं कर रहा हूँ)

    अन्य तरीकों

  • विस्तृत शृंखला को बनाने के लिए उन्हें गुजर

ढेर का उपयोग करें जब:

  • आप एक वस्तु है कि रहता है और विधि

  • वस्तु या एक सीपीयू रजिस्टर के आकार छोटे

+0

बस जो कुछ भी आप यहां कहते हैं उसके बारे में गलत है। –

+0

हाँ, आप बहुत गलत हैं। –

+0

तो आप दोनों: स्टैक पर ऑब्जेक्ट पास करें, ढेर पर बड़े सरणी बनाएं, ढेर पर स्थानीय चर आवंटित करें, ढेर पर पूर्णांक आवंटित करें? – LegendLength

0

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

जहां संभव हो वहां गुजरने वाले पैरामीटर के संदर्भों का उपयोग करें।

+0

int x; int * pointer_to_x = & x; आप पॉइंटर्स और ढेर आवंटन के बीच ओपी के भ्रम को दोहरा रहे हैं। –

+0

नहीं, मूल्य के बजाय कॉन्स संदर्भ द्वारा गुजरना एक अच्छी आदत है। हालांकि यह कार्यान्वयन स्तर पर पॉइंटर्स का उपयोग करता है, लेकिन उनके पास अवधारणात्मक रूप से उनके साथ कुछ लेना देना नहीं है। –

4

आप आम तौर पर निम्न परिदृश्यों में संकेत का उपयोग करना होगा:

  1. आप वस्तुओं है कि विभिन्न वर्गों के हैं का एक संग्रह की जरूरत है (ज्यादातर मामलों में वे एक आम आधार होगा)।

  2. आपको ऑब्जेक्ट्स का एक स्टैक-आवंटित संग्रह इतना बड़ा होना चाहिए कि इससे स्टैक ओवरफ़्लो हो सकता है।

  3. आपको एक डेटा संरचना की आवश्यकता है जो वस्तुओं को त्वरित रूप से पुनर्व्यवस्थित कर सकता है - जैसे एक लिंक की गई सूची, पेड़ आर समान है।

  4. आप अपने वस्तु के लिए जीवन भर प्रबंधन के कुछ जटिल तर्क की जरूरत है। एक लिंक्ड सूची, पेड़ या किसी अन्य ग्राफ की तरह -

  5. आप एक डेटा संरचना है कि विरोध करने वस्तु से प्रत्यक्ष नेविगेशन के लिए अनुमति देता है की जरूरत है।

+0

(1) के मामले में एक सामान्य आधार की आवश्यकता के बारे में "शायद" नहीं है। (2) के मामले में केवल "संग्रह" जहां यह लागू होगा एक सी-शैली सरणी होगी। –

+0

मामले के लिए (1) यह जरूरी नहीं है, आप केवल शून्य() को कॉल करने में सक्षम होने के लिए शून्य * की एक सरणी स्टोर करना चाह सकते हैं - यह चीजों को करने का सी ++ तरीका नहीं है, लेकिन हो सकता है। मामले के लिए (2) मेरा मतलब वास्तविक वस्तुओं की एक सरणी बनाम पॉइंटर्स की एक सरणी थी। यदि ऑब्जेक्ट्स वास्तव में बड़े भंडारण पॉइंटर्स हैं तो अधिक स्टैक स्पेस बचाएं। – sharptooth

2

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

+0

यह वास्तव में एक बहुत ही भयानक विचार है। अंतिम, बोल्ड, पैराग्राफ के लिए –

1

मैं वास्तव में इस स्थिति में संकेत का उपयोग करें:

class Foo 
{ 
    Bar* bar; 

    Foo(Bar& bar) : bar(&bar) { } 

    Bar& Bar() const { return *bar; } 
}; 

इससे पहले, मैं संदर्भ के सदस्यों, निर्माता से प्रारंभ करते थे, लेकिन संकलक प्रतिलिपि कंस्ट्रक्टर्स, असाइनमेंट ऑपरेटर, और बहुत कुछ बनाने में कोई समस्या नहीं है।

डेव

15

यह मेरे लिए स्पष्ट नहीं है अगर आपके प्रश्न ptr करने वाली obj बनाम है ढेर आधारित obj या ptr करने वाली obj बनाम संदर्भ करने वाली obj। ऐसे उपयोग भी हैं जो किसी भी श्रेणी में नहीं आते हैं।

बनाम स्टैक के बारे में, जो पहले से ही ऊपर से ढंका हुआ प्रतीत होता है। कई कारण, सबसे स्पष्ट वस्तु का जीवनकाल है।

संदर्भ बनाम के बारे में, हमेशा संदर्भ का उपयोग करने का प्रयास करते है, लेकिन वहाँ बातें आप केवल ptrs साथ, उदाहरण के लिए (वहाँ कई उपयोग हैं) कर सकते हैं:

  • एक सरणी में तत्वों के माध्यम से चलने के लिए (जैसे, मार्चिंग एक मानक सरणी [])
  • जब एक बुलाया समारोह कुछ & एक ptr

सबसे महत्वपूर्ण बात, संकेत (और संदर्भ, के रूप में स्वत: करने का विरोध किया/ढेर आधारितके माध्यम से इसे रिटर्न आवंटित से अधिकस्थैतिक वस्तुओं) समर्थन polymorphism। बेस क्लास के लिए पॉइंटर वास्तव में व्युत्पन्न कक्षा को इंगित कर सकता है। यह सी ++ में समर्थित ओओ व्यवहार के लिए मूलभूत है।

+3

+1, क्योंकि मैं इसे और अधिक नहीं बढ़ा सकता। –

+0

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

10

सबसे पहले, सवाल गलत है: दुविधा पॉइंटर्स और ढेर के बीच नहीं है, लेकिन ढेर और ढेर के बीच है। आपके पास स्टैक पर ऑब्जेक्ट हो सकता है और उस ऑब्जेक्ट पर पॉइंटर पास कर सकता है। मैं मानता हूं कि आप वास्तव में क्या पूछ रहे हैं कि क्या आपको कक्षा में एक पॉइंटर घोषित करना चाहिए या कक्षा का उदाहरण देना चाहिए।

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

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

1

संकेत का उपयोग कर दो ओर्थोगोनल चीजों के साथ जुड़ा हुआ है:

  1. गतिशील आवंटन। आम तौर पर, आपको गतिशील रूप से आवंटित करना चाहिए, जब ऑब्जेक्ट का उद्देश्य लंबे समय तक जीने का इरादा है, जिस क्षेत्र में यह बनाया गया है। ऐसी वस्तु एक संसाधन है जिसे मालिक को स्पष्ट रूप से निर्दिष्ट किया जाना चाहिए (आमतौर पर कुछ प्रकार के स्मार्ट सूचक)।

  2. पते द्वारा एक्सेस (चाहे वस्तु कैसे बनाई गई थी)। इस संदर्भ में सूचक का स्वामित्व का मतलब नहीं है। इस तरह की पहुंच की आवश्यकता हो सकती है जब:

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

# 1 और # 2 अलग विन्यास में हो सकता है, उदाहरण के लिए आप सूचक द्वारा पहुँचा गतिशील आवंटित वस्तु कल्पना कर सकते हैं, लेकिन इस तरह वस्तु भी द्वारा कुछ कार्य करने के लिए संदर्भ द्वारा पारित कर सकता है। आप स्टैक पर बनाए गए कुछ ऑब्जेक्ट पर पॉइंटर भी प्राप्त कर सकते हैं, आदि

+0

"दो ऑर्थोगोनल चीजें" - आखिरकार, किसी ने यह कहा! [सीएफ] (http://stackoverflow.com/questions/658133/c-when-to-use-pointers#comment63979527_658308) मैं बिंदु ** 2 ** में जोड़ूंगा जो संदर्भ/सूचक (= पता) द्वारा एक्सेसिंग polymorphism को सक्षम बनाता है , इस बात पर ध्यान दिए बिना कि ऑब्जेक्ट आवंटित किया गया था - पोस्ट की भयानक संख्या के विपरीत मुझे लगता है कि गतिशील आवंटन का एक वैध कारण बहुरूप व्यवहार प्रदान करना है - जो आवश्यक नहीं है, तर्क नहीं है, और पूरी तरह से असंबंधित है। –

1

अच्छी तरह से व्यवहार की गई प्रतिलिपि वस्तुओं के साथ मूल्य से गुजरना आपके कोड की बड़ी मात्रा के लिए जाने का तरीका है।

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

0

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

विशेष रूप से क्यूटी के बारे में बोलते हुए, क्यूटी प्रोग्रामर को ढेर वस्तुओं के बहुत सारे मेमोरी प्रबंधन को संभालने में मदद करता है। QObject से प्राप्त वस्तुओं के लिए ("Q" द्वारा उपसर्ग किए गए लगभग सभी वर्ग हैं), निर्माता वैकल्पिक पैरामीटर माता-पिता लेते हैं। अभिभावक तब ऑब्जेक्ट का मालिक होता है, और जब माता-पिता को हटा दिया जाता है, तो सभी स्वामित्व वाली वस्तुएं भी हटा दी जाती हैं। संक्षेप में, बच्चों के विनाश की ज़िम्मेदारी मूल वस्तु को दी जाती है। इस तंत्र का उपयोग करते समय, बच्चे QObject एस ढेर पर बनाया जाना चाहिए।

संक्षेप में, क्यूटी में आप आसानी से ढेर पर ऑब्जेक्ट बना सकते हैं, और जब तक आप एक उचित माता-पिता को सेट करते हैं, तो आपको केवल माता-पिता को नष्ट करने की चिंता करनी होगी। सामान्य सी ++ में, हालांकि, आपको ढेर वस्तुओं को नष्ट करने, या स्मार्ट पॉइंटर्स का उपयोग करने की याद रखना होगा।

1

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

जावा का पॉइंटर्स नहीं होने का एक कारण है। सी ++ को या तो उनकी आवश्यकता नहीं है।यदि आप उनके उपयोग से बचते हैं तो ऑब्जेक्ट स्कोप छोड़ने पर आपको स्वचालित ऑब्जेक्ट विनाश का अतिरिक्त लाभ मिलेगा। अन्यथा आपका कोड विभिन्न प्रकार की स्मृति त्रुटियों को उत्पन्न करेगा। अनचाहे अपवादों के कारण मेमोरी लीक खोजने के लिए बहुत मुश्किल हो सकती है और अक्सर सी ++ में होती है।

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

+1

खैर, जावा में "पॉइंटर्स" नहीं हैं क्योंकि आदिम के अलावा अन्य सब कुछ एक सूचक है। – mk12

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