C ++: स्मार्ट पॉइंटर्स, रॉ पॉइंटर्स, नो पॉइंटर्स? [बन्द है]


48

C ++ में गेम विकसित करने के दायरे में, पॉइंटर्स के उपयोग के संबंध में आपके पसंदीदा पैटर्न क्या हैं (यह कोई नहीं, कच्चा, स्कोप्ड, साझा, या अन्यथा स्मार्ट और गूंगे के बीच में है)?

आप विचार कर सकते हैं

  • वस्तु स्वामित्व
  • उपयोग में आसानी
  • कॉपी पॉलिसी
  • भूमि के ऊपर
  • चक्रीय संदर्भ
  • लक्ष्य मंच
  • कंटेनरों के साथ उपयोग करें

जवाबों:


32

विभिन्न तरीकों की कोशिश करने के बाद, आज मैं खुद को Google C ++ स्टाइल गाइड के साथ संरेखण में पाता हूं :

यदि आपको वास्तव में सूचक शब्दार्थ की आवश्यकता है, तो scoped_ptr महान है। आपको केवल std :: tr1 :: share_ptr का उपयोग बहुत ही विशिष्ट परिस्थितियों में करना चाहिए, जैसे कि वस्तुओं को STL कंटेनरों द्वारा रखने की आवश्यकता होती है। आपको कभी भी auto_ptr का उपयोग नहीं करना चाहिए। [...]

सामान्यतया, हम पसंद करते हैं कि हम स्पष्ट वस्तु स्वामित्व के साथ कोड डिजाइन करते हैं। स्पष्ट वस्तु का स्वामित्व किसी क्षेत्र या स्थानीय चर के रूप में सीधे किसी वस्तु का उपयोग करके प्राप्त किया जाता है, बिना पॉइंटर्स का उपयोग किए। [..]

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


14
आज, आप scded_ptr के बजाय std :: unique_ptr का उपयोग करना चाह सकते हैं।
14

24

मैं विचार की "मजबूत स्वामित्व" ट्रेन का भी पालन करता हूं। मुझे स्पष्ट रूप से यह पसंद है कि "यह वर्ग इस सदस्य का मालिक है" जब यह उपयुक्त हो।

मैं शायद ही कभी उपयोग करता हूं shared_ptr। यदि मैं करता हूं, तो weak_ptrजब भी मैं ऐसा कर सकता हूं, का उदारवादी उपयोग करता हूं ताकि मैं संदर्भ संख्या बढ़ाने के बजाय इसे ऑब्जेक्ट के हैंडल की तरह मान सकूं।

मैं scoped_ptrसभी जगह का उपयोग करता हूं । यह स्पष्ट स्वामित्व दर्शाता है। एकमात्र कारण यह है कि मैं वस्तुओं को उस तरह से नहीं बनाता हूं क्योंकि आप एक scoped_ptr में होने पर उन्हें आगे घोषित कर सकते हैं।

यदि मुझे वस्तुओं की सूची चाहिए, तो मैं उपयोग करता हूं ptr_vector। यह अधिक कुशल है और उपयोग करने की तुलना में कम दुष्प्रभाव है vector<shared_ptr>। मुझे लगता है कि आप आगे ptr_vector में प्रकार की घोषणा करने में सक्षम नहीं हो सकते हैं (यह थोड़ी देर हो गई है), लेकिन इसके शब्दार्थ इसे मेरे विचार से इसके लायक बनाते हैं। मूल रूप से यदि आप सूची से किसी ऑब्जेक्ट को हटाते हैं तो यह स्वचालित रूप से हटा दिया जाता है। यह स्पष्ट स्वामित्व भी दर्शाता है।

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

इस पद्धति के साथ, मैंने जिस एक iPhone गेम पर काम किया, वह केवल एक deleteकॉल करने में सक्षम था , और वह ओब्ज-सी से सी ++ पुल मैंने लिखा था।

आम तौर पर मेरी राय है कि मनुष्यों को छोड़ने के लिए स्मृति प्रबंधन बहुत महत्वपूर्ण है। यदि आप विलोपन को स्वचालित कर सकते हैं, तो आपको करना चाहिए। यदि साझा समय पर ओवरहेड से ओवरहेड बहुत महंगा है (यह मानते हुए कि आपने थ्रेडिंग सपोर्ट, आदि को बंद कर दिया है), तो आपको अपने डायनेमिक आवंटन को प्राप्त करने के लिए संभवतः कुछ और (यानी एक बाल्टी पैटर्न) का उपयोग करना चाहिए।


1
बहुत बढ़िया सारांश। क्या आपका वास्तव में मतलब है कि आपके पास स्मार्ट_प्ट्र के उल्लेख के विपरीत साझा किया गया है?
jmp97

हां, मेरा मतलब share_ptr था। मैं ठीक कर दूँगा।
टेट्राद

10

इस काम के लिए सही उपकरण का उपयोग करें।

यदि आपका प्रोग्राम अपवादों को फेंक सकता है तो सुनिश्चित करें कि आपका कोड अपवाद है। स्मार्ट पॉइंटर्स का उपयोग करना, आरएआईआई, और 2 चरण के निर्माण से बचना अच्छे शुरुआती बिंदु हैं।

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

अच्छी लाइब्रेरी आपको अवधारणा को कोड करने की अनुमति देंगी न कि प्रकार ताकि यह ज्यादातर मामलों में मायने नहीं रखे जो कि आप किस प्रकार के पॉइंटर का उपयोग संसाधन संसाधन समस्याओं से परे कर रहे हैं।

यदि आप एक बहु-थ्रेडेड वातावरण में काम कर रहे हैं, तो सुनिश्चित करें कि आप समझते हैं कि आपकी वस्तु संभावित रूप से थ्रेड्स में साझा की गई है या नहीं। बढ़ावा का उपयोग करने पर विचार करने के लिए मुख्य कारणों में से एक :: share_ptr या std :: tr1 :: share_ptr क्योंकि यह एक थ्रेड-सुरक्षित संदर्भ गणना का उपयोग करता है।

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

अगर आपको साझा स्वामित्व की आवश्यकता है, लेकिन संदर्भ की लागत का भुगतान नहीं करना चाहते हैं या कचरा संग्रह अपरिवर्तनीय वस्तुओं का उपयोग करने पर विचार करें या मुहावरे पर एक प्रति लिखें।

ध्यान रखें कि आपके सबसे बड़े प्रदर्शन जीत दूर और वास्तुकला स्तर पर होने वाले हैं, इसके बाद एक एल्गोरिथ्म स्तर होता है, और जब ये निम्न स्तर की चिंताएं बहुत महत्वपूर्ण होती हैं, तो आपको प्रमुख मुद्दों को संबोधित करने के बाद ही निपटना चाहिए। यदि आप कैशे मिस के स्तर पर प्रदर्शन के मुद्दों से निपट रहे हैं, तो आपके पास मुद्दों की एक पूरी मेजबानी है जिसे आपको झूठी साझाकरण के बारे में भी जागरूक होना होगा, जिसका कहना है कि प्रति संकेत के साथ कोई लेना-देना नहीं है।

यदि आप केवल स्मार्ट पॉइंटर्स का उपयोग कर रहे हैं, तो टेक्स्ट या मॉडल जैसे संसाधनों को साझा करने के लिए Boost.Flyweight जैसे अधिक विशिष्ट पुस्तकालय पर विचार करें।

एक बार जब नया मानक चालित शब्दार्थ बन जाता है, संदर्भों को फिर से जोड़ा जाता है, और सही अग्रेषण महंगी वस्तुओं और कंटेनरों के साथ काम करना आसान और अधिक कुशल बना देगा। तब तक एक कंटेनर (मानक अवधारणा) में, विध्वंसक प्रतिलिपि शब्दार्थ के साथ पॉइंटर्स को संग्रहीत न करें, जैसे कि auto_ptr या unique_ptr। Boost.Pointer कंटेनर लाइब्रेरी का उपयोग करने या कंटेनरों में साझा स्वामित्व वाले स्मार्ट पॉइंटर्स को संग्रहीत करने पर विचार करें। प्रदर्शन क्रिटिकल कोड में आप बूस्ट.इंट्रूसिव जैसे घुसपैठ वाले कंटेनर के पक्ष में इन दोनों से बचने पर विचार कर सकते हैं।

लक्ष्य प्लेटफ़ॉर्म वास्तव में आपके निर्णय को बहुत अधिक प्रभावित नहीं करना चाहिए। एंबेडेड डिवाइस, स्मार्ट फोन, डंबल फोन, पीसी, और कंसोल सभी ठीक कोड चला सकते हैं। परियोजना की आवश्यकताएं जैसे सख्त मेमोरी बजट या कोई गतिशील आवंटन कभी नहीं / लोड के बाद अधिक वैध चिंताएं हैं और आपकी पसंद को प्रभावित करना चाहिए।


3
कंसोल्स पर एक्सेप्शन हैंडलिंग थोड़ी डोडी हो सकती है - विशेष रूप से एक्सडीके अपवाद-शत्रुतापूर्ण है।
क्रैशवर्क्स

1
लक्ष्य मंच वास्तव में आपके डिजाइन को प्रभावित करना चाहिए। आपके डेटा को बदलने वाला हार्डवेयर कभी-कभी आपके स्रोत-कोड पर बड़ा प्रभाव डाल सकता है। PS3-आर्किटेक्चर एक ठोस उदाहरण है जहां आपको वास्तव में अपने संसाधन और मेमोरी-मैनेजमेंट के साथ-साथ अपने रेंडर को डिजाइन करने में हार्डवेयर की आवश्यकता होती है।
शमौन

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

4

यदि आप C ++ 0x का उपयोग कर रहे हैं, तो उपयोग करें std::unique_ptr<T>

इसके पास कोई प्रदर्शन ओवरहेड नहीं है, std::shared_ptr<T>जिसके विपरीत संदर्भ गिनती ओवरहेड है। एक Unique_ptr इसके सूचक का मालिक है , और आप C ++ 0x के चाल शब्दार्थ के साथ स्वामित्व स्थानांतरित कर सकते हैं । आप उन्हें कॉपी नहीं कर सकते - केवल उन्हें स्थानांतरित कर सकते हैं।

इसका उपयोग कंटेनरों में भी किया जा सकता है, उदाहरण के लिए std::vector<std::unique_ptr<T>>, जो बाइनरी-संगत और प्रदर्शन में समान है std::vector<T*>, लेकिन यदि आप तत्वों को मिटाते हैं या वेक्टर को साफ़ करते हैं, तो यह मेमोरी को लीक नहीं करेगा। यह भी एसटीएल एल्गोरिदम के साथ बेहतर संगतता है ptr_vector

बहुत सारे उद्देश्यों के लिए IMO यह एक आदर्श कंटेनर है: रैंडम एक्सेस, अपवाद सुरक्षित, मेमोरी लीक को रोकता है, वेक्टर रिक्लेक्शन के लिए कम ओवरहेड (सिर्फ पर्दे के पीछे पॉइंटर्स के आसपास फेरबदल)। कई उद्देश्यों के लिए बहुत उपयोगी है।


3

यह दस्तावेज़ के लिए अच्छा अभ्यास है कि कौन से वर्ग किस बिंदु के मालिक हैं। अधिमानतः, आप सामान्य वस्तुओं का उपयोग करते हैं, और जब भी आप कर सकते हैं कोई संकेत नहीं।

हालांकि, जब आपको संसाधनों पर नज़र रखने की आवश्यकता होती है, तो पासिंग पॉइंटर्स एकमात्र विकल्प होता है। कुछ मामले हैं:

  • आप पॉइंटर को कहीं और से प्राप्त करते हैं, लेकिन इसे प्रबंधित न करें: बस एक सामान्य पॉइंटर का उपयोग करें और इसे दस्तावेज करें ताकि आप इसे हटाने की कोशिश करने के बाद कोई कोडर न करें।
  • आपको सूचक कहीं और से मिलता है, और आप इसका ट्रैक रखते हैं: scoped_ptr का उपयोग करें।
  • आपको पॉइंटर कहीं और से मिलता है, और आप इसका ट्रैक रखते हैं लेकिन इसे हटाने के लिए एक विशेष विधि की आवश्यकता होती है: एक कस्टम डिलीट विधि के साथ साझा करें।
  • आपको एसटीएल कंटेनर में पॉइंटर की आवश्यकता है: यह चारों ओर कॉपी किया जाएगा ताकि आपको बढ़ावा देने की आवश्यकता हो :: साझा किया गया।
  • कई कक्षाएं सूचक को साझा करती हैं, और यह स्पष्ट नहीं है कि कौन इसे हटा देगा: साझा_प्रति (ऊपर का मामला वास्तव में इस बिंदु का एक विशेष मामला है)।
  • आप सूचक स्वयं बनाते हैं और केवल आपको इसकी आवश्यकता होती है: यदि आप वास्तव में एक सामान्य वस्तु का उपयोग नहीं कर सकते हैं: scoped_ptr।
  • आप पॉइंटर बनाते हैं और इसे अन्य वर्गों के साथ साझा करेंगे: शेयर्ड_एप्ट्र।
  • आप पॉइंटर बनाते हैं और इसे पास करते हैं: एक सामान्य पॉइंटर का उपयोग करें और अपने इंटरफ़ेस का दस्तावेज़ीकरण करें ताकि नए मालिक को पता चले कि उसे स्वयं संसाधन का प्रबंधन करना चाहिए!

मुझे लगता है कि मैं अभी अपने संसाधनों का प्रबंधन कैसे करता हूं, इसमें बहुत कुछ शामिल है। शेयर्ड_प्ट्र जैसे पॉइंटर की मेमोरी कॉस्ट सामान्य पॉइंटर की मेमोरी कॉस्ट से दोगुनी होती है। मुझे नहीं लगता कि यह ओवरहेड बहुत बड़ा है, लेकिन यदि आप संसाधनों पर कम हैं, तो आपको स्मार्ट पॉइंटर्स की संख्या को कम करने के लिए अपने गेम को डिजाइन करने पर विचार करना चाहिए। अन्य मामलों में मैं ऊपर दिए गए गोलियों जैसे अच्छे सिद्धांतों को डिजाइन करता हूं और प्रोफाइलर मुझे बताएगा कि मुझे कहां और अधिक गति की आवश्यकता होगी।


1

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

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

यह एक समयपूर्व अनुकूलन नहीं है, यह एक स्वस्थ निर्णय है जिसे जल्द से जल्द लिया जा सकता है और लिया जाना चाहिए। यह हार्डवेयर की वास्तुशिल्प समझ का सवाल है जो आपके सॉफ़्टवेयर पर चलेगा और यह महत्वपूर्ण है।

संपादित करें: साझा-संकेतकर्ताओं के प्रदर्शन के बारे में विचार करने के लिए कुछ चीजें हैं:

  • संदर्भ काउंटर को आवंटित किया गया है।
  • यदि आप थ्रेड-सेफ्टी इनेबल का उपयोग करते हैं, तो रेफरेंस काउंटिंग इंटरलॉक किए गए ऑपरेशंस के जरिए की जाती है।
  • पॉइंटर को वैल्यू द्वारा पास करना रेफरेंस काउंट को संशोधित करता है, जिसका अर्थ है कि इंटरलॉक किए गए ऑपरेशन का सबसे अधिक संभावना है कि मेमोरी में रैंडम एक्सेस का उपयोग करें (ताले + संभावना कैश)।

2
आपने मुझे 'हर कीमत पर टाल' दिया। फिर आप एक प्रकार के अनुकूलन का वर्णन करते हैं जो वास्तविक दुनिया के खेल के लिए एक चिंता का विषय है। अधिकांश गेम डेवलपमेंट की विशेषता विकास की समस्याएं (देरी, बग, बजाना आदि) हैं, जो सीपीयू कैश प्रदर्शन की कमी से नहीं होती हैं। इसलिए मैं इस विचार से पूरी तरह असहमत हूं कि यह सलाह समयपूर्व अनुकूलन नहीं है।
केविन42

2
मुझे डेटा लेआउट के शुरुआती डिजाइन से सहमत होना होगा। आधुनिक कंसोल / मोबाइल डिवाइस से किसी भी प्रदर्शन को प्राप्त करना महत्वपूर्ण है और यह एक ऐसी चीज है जिसे कभी भी ओवर-लुक नहीं किया जाना चाहिए।
ऑली

1
यह एक ऐसा मुद्दा है जिसे मैंने AAA-स्टूडियो में देखा है, जिस पर मैं काम कर रहा हूं। आप इनसोम्नियाक गेम्स, माइक एक्टन में हेड आर्किटेक्ट को भी सुन सकते हैं। मैं यह नहीं कह रहा हूं कि बढ़ावा एक बुरी लाइब्रेरी है, यह उच्च प्रदर्शन वाले खेलों के लिए बिल्कुल उपयुक्त नहीं है।
साइमन

1
@ केविन 42: आज खेल विकास में कम-स्तरीय अनुकूलन का मुख्य स्रोत कैशे सुसाइड है। @Simon: अधिकांश शेयर्ड_पार्ट कार्यान्वयन किसी भी प्लेटफ़ॉर्म पर ताले से बचते हैं जो तुलना-और-स्वैप का समर्थन करता है, जिसमें लिनक्स और विंडोज पीसी शामिल हैं, और मेरा मानना ​​है कि इसमें Xbox भी शामिल है।

1
@ जोए रेसेचिग: यह सच है, कैश-मिस अभी भी सबसे अधिक संभावना है, हालांकि साझा-पॉइंटर (प्रतिलिपि, कमजोर पॉइंटर आदि से बनाएं) के किसी भी आरंभीकरण का कारण बनता है। आधुनिक पीसी पर एक L2 कैश-मिस 200 चक्रों की तरह है और पीपीसी (Xbox360 / ps3) पर यह अधिक है। एक गहन गेम के साथ आपके पास 1000 तक गेम ऑब्जेक्ट हो सकते हैं, यह देखते हुए कि प्रत्येक गेम ऑब्जेक्ट में कुछ संसाधन हो सकते हैं, हम उन मुद्दों को देख रहे हैं जहां उनका स्केलिंग एक प्रमुख चिंता का विषय है। यह संभवतः एक विकास चक्र के अंत में मुद्दों का कारण होगा (जब आप गेम ऑब्जेक्ट की उच्च मात्रा को हिट करेंगे)।
साइमन

0

मैं हर जगह स्मार्ट पॉइंटर्स का उपयोग करता हूं। मुझे यकीन नहीं है कि यह पूरी तरह से एक अच्छा विचार है, लेकिन मैं आलसी हूं, और मैं किसी भी वास्तविक नकारात्मक को नहीं देख सकता हूं [सिवाय इसके कि मैं कुछ सी-स्टाइल सूचक अंकगणित करना चाहता था]। मैं बढ़ावा देने का उपयोग करता हूं :: साझा किया गया_ क्योंकि मुझे पता है कि मैं इसे चारों ओर कॉपी कर सकता हूं - अगर दो इकाइयां एक छवि साझा करती हैं, तो अगर एक मर जाता है तो दूसरे को छवि भी नहीं खोनी चाहिए।

इसका नकारात्मक पक्ष यह है कि यदि कोई वस्तु किसी ऐसी चीज को हटाती है जो उसे इंगित करती है और उसका मालिक है, लेकिन कुछ और भी उसे इंगित कर रहा है, तो वह नष्ट नहीं होता है।


1
मैं लगभग हर जगह share_ptr का उपयोग कर रहा हूं, लेकिन - लेकिन आज मैं यह सोचने की कोशिश करता हूं कि क्या मुझे वास्तव में डेटा के कुछ टुकड़े के लिए साझा स्वामित्व की आवश्यकता है या नहीं। यदि नहीं, तो उस डेटा को मूल डेटा संरचना में एक गैर-पॉइंटर सदस्य बनाना उचित होगा। मुझे लगता है कि स्पष्ट स्वामित्व डिजाइन को सरल करता है।
11:25 पर jp97

0

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


0

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

काम पर, निश्चित रूप से, सभी अलग-अलग हैं, जब तक कि मैं प्रोटोटाइप नहीं कर रहा हूं, जो मुझे शुक्र है कि मुझे बहुत कुछ करना है।


0

लगभग कोई नहीं, हालांकि यह वास्तव में एक अजीब जवाब है, और शायद सभी के लिए उपयुक्त कहीं नहीं है।

लेकिन मैंने अपने व्यक्तिगत मामले में एक विशेष प्रकार के सभी उदाहरणों को एक केंद्रीय, रैंडम-एक्सेस सीक्वेंस (थ्रेड-सेफ) में संग्रहीत करने के लिए, और इसके बजाय 32-बिट सूचकांकों (सापेक्ष पते, अर्थात) के साथ काम करने के लिए इसे और अधिक उपयोगी पाया है। बल्कि निरपेक्ष संकेत की तुलना में।

एक शुरुआत के लिए:

  1. यह 64-बिट प्लेटफार्मों पर एनालॉग पॉइंटर की मेमोरी आवश्यकताओं को आधा कर देता है। अब तक मुझे किसी विशेष डेटा प्रकार के ~ 4.29 बिलियन से अधिक उदाहरणों की आवश्यकता नहीं है।
  2. यह सुनिश्चित करता है कि किसी विशेष प्रकार के सभी उदाहरण T, कभी भी स्मृति में बिखरे हुए नहीं होंगे। यह सभी प्रकार के एक्सेस पैटर्न के लिए कैश मिस को कम करने के लिए जाता है, यहां तक ​​कि पेड़ों की तरह जुड़े संरचनाओं को भी खोदता है यदि नोड्स को सूचक के बजाय सूचक का उपयोग करके एक साथ जोड़ा जाता है।
  3. समानांतर डेटा पेड़ों या हैश तालिकाओं के बजाय सस्ते समानांतर सरणियों (या विरल सरणियों) का उपयोग करना आसान हो जाता है।
  4. समानांतर चौराहे पर सेट चौराहों को रैखिक-समय पर या बेहतर उपयोग करके कहा जा सकता है।
  5. हम सूचकांक को क्रमबद्ध कर सकते हैं और एक बहुत ही कैश-फ्रेंडली अनुक्रमिक एक्सेस पैटर्न प्राप्त कर सकते हैं।
  6. हम इस बात पर नज़र रख सकते हैं कि किसी विशेष डेटा प्रकार के कितने उदाहरण आवंटित किए गए हैं।
  7. उन स्थानों की संख्या को कम करता है जिन्हें अपवाद-सुरक्षा जैसी चीजों से निपटना पड़ता है, अगर आप उस तरह की परवाह करते हैं।

उस ने कहा, सुविधा एक नकारात्मक पहलू है और साथ ही प्रकार की सुरक्षा भी है। हम कंटेनर और इंडेक्स दोनोंT तक पहुंच के बिना इंस्टेंस का उपयोग नहीं कर सकते । और एक पुराना पुराना हमें बताता है कि वह किस प्रकार का डेटा संदर्भित करता है, इसलिए कोई प्रकार की सुरक्षा नहीं है। हम गलती से किसी इंडेक्स का उपयोग करके एक्सेस करने का प्रयास कर सकते हैं । दूसरी समस्या को कम करने के लिए मैं अक्सर इस तरह की बात करता हूं:int32_tBarFoo

struct FooIndex
{
    int32_t index;
};

जो एक तरह से मूर्खतापूर्ण लगता है, लेकिन यह मुझे प्रकार की सुरक्षा वापस देता है ताकि लोग गलती Barसे Fooएक संकलक त्रुटि के बिना एक सूचकांक के माध्यम से एक्सेस करने का प्रयास न कर सकें । सुविधा पक्ष के लिए, मैं बस थोड़ी सी असुविधा को स्वीकार करता हूं।

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

के रूप में shared_ptr, मैं इसे इतना उपयोग नहीं करने की कोशिश करता हूं। ज्यादातर समय मुझे नहीं लगता कि यह स्वामित्व साझा करने के लिए समझ में आता है, और इतनी जल्दबाजी करने से तार्किक लीक हो सकती है। अक्सर कम से कम उच्च स्तर पर, एक चीज एक चीज से संबंधित होती है। जहाँ मुझे अक्सर यह पता चलता है कि इसका उपयोग करने का प्रलोभन उन shared_ptrस्थानों में किसी वस्तु के जीवनकाल का विस्तार कर रहा है जो वास्तव में स्वामित्व के साथ सौदा नहीं करते थे, जैसे कि थ्रेड समाप्त होने से पहले ऑब्जेक्ट को नष्ट नहीं किया जाता है यह सुनिश्चित करने के लिए धागे में सिर्फ एक स्थानीय फ़ंक्शन। उसका इस्तेमाल कर रहे हैं।

उस समस्या से निपटने के लिए, shared_ptrGC या उसके जैसे कुछ का उपयोग करने के बजाय , मैं अक्सर थ्रेड पूल से चलने वाले अल्पकालिक कार्यों का पक्ष लेता हूं, और ऐसा करता हूं कि अगर वह धागा किसी वस्तु को नष्ट करने का अनुरोध करता है, तो वास्तविक विनाश एक सुरक्षित के लिए स्थगित कर दिया जाता है वह समय जब सिस्टम यह सुनिश्चित कर सकता है कि किसी भी प्रकार को ऑब्जेक्ट ऑब्जेक्ट प्रकार तक पहुंचने की आवश्यकता नहीं है।

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

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

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