c++ - क्या मुझे सदस्य डेटा में पॉइंटर्स या संदर्भ पसंद करना चाहिए?




reference class-members (6)

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

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

प्रश्न को स्पष्ट करने के लिए यह एक सरल उदाहरण है:

class A {};

class B
{
    B(A& a) : a(a) {}
    A& a;
};

class C
{
    C() : b(a) {} 
    A a;
    B b; 
};

तो बी सी के एक हिस्से को अद्यतन करने के लिए ज़िम्मेदार है। मैंने कोड के माध्यम से कोड चलाया और यह संदर्भ सदस्य के बारे में चिल्लाया: lint#1725 । डिफ़ॉल्ट प्रतिलिपि और असाइनमेंट पर सावधानी बरतने के बारे में यह वार्तालाप पर्याप्त है, लेकिन डिफ़ॉल्ट प्रतिलिपि और असाइनमेंट पॉइंटर्स के साथ भी खराब है, इसलिए वहां थोड़ा सा फायदा है।

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

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

क्या यह कहना सही है कि किसी संदर्भ वाले ऑब्जेक्ट को असाइन करने योग्य नहीं होना चाहिए, क्योंकि एक बार प्रारंभ किए जाने के बाद संदर्भ नहीं बदला जाना चाहिए?


अंगूठे का मेरा नियम:

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

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

ऐसे मामलों में, असाइनमेंट ऑपरेटर (और अक्सर कॉपी कन्स्ट्रक्टर) को गैर-उपयोग करने योग्य ( boost::noncopyable गैर- boost::noncopyable या उन्हें निजी घोषित करने से) प्राप्त करना सुनिश्चित करें।

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


जैसा कि हर कोई सामान्य नियमों को सौंप रहा है, मैं दो पेशकश करूंगा:

  • कक्षा के सदस्यों के रूप में कभी भी उपयोग संदर्भों का उपयोग न करें। मैंने अपने कोड में कभी ऐसा नहीं किया है (खुद को यह साबित करने के अलावा कि मैं इस नियम में सही था) और ऐसे मामले की कल्पना नहीं कर सकता जहां मैं ऐसा करूँगा। अर्थशास्त्र बहुत उलझन में हैं, और वास्तव में यह नहीं है कि संदर्भ किस लिए डिजाइन किए गए थे।

  • हमेशा, हमेशा, बुनियादी प्रकारों को छोड़कर, या जब एल्गोरिदम को प्रतिलिपि की आवश्यकता होती है, कार्यों के पैरामीटर पास करते समय संदर्भों का उपयोग करें।

ये नियम सरल हैं, और मुझे अच्छी स्थिति में खड़ा कर दिया है। मैं क्लाइंट सदस्यों के रूप में स्मार्ट पॉइंटर्स (लेकिन कृपया, auto_ptr नहीं) का उपयोग करने पर नियम बनाना छोड़ देता हूं।


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

उदाहरण की समस्याएं:

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

हां: क्या यह कहना सही है कि किसी संदर्भ वाले ऑब्जेक्ट को असाइन करने योग्य नहीं होना चाहिए, क्योंकि एक बार प्रारंभ किए जाने के बाद कोई संदर्भ नहीं बदला जाना चाहिए?

डेटा सदस्यों के लिए अंगूठे के मेरे नियम:

  • कभी भी संदर्भ का उपयोग न करें, क्योंकि यह असाइनमेंट को रोकता है
  • यदि आपकी कक्षा हटाने के लिए ज़िम्मेदार है, तो बूस्ट के scoped_ptr का उपयोग करें (जो auto_ptr से सुरक्षित है)
  • अन्यथा, एक सूचक या कॉन्स सूचक का उपयोग करें




class-members