2010-03-05 12 views
16

कहें कि मुझे एक कक्षा मिली है जहां एकमात्र डेटा सदस्य std::string या std::vector जैसा कुछ है। क्या मुझे एक कॉपी कन्स्ट्रक्टर, विनाशक और असाइनमेंट ऑपरेटर प्रदान करने की आवश्यकता है?मेरी सी ++ कक्षा के लिए मुझे किन परिस्थितियों में, असाइनमेंट ऑपरेटर, कॉपी कन्स्ट्रक्टर और विनाशक प्रदान करना चाहिए?

उत्तर

10

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

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

0

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

+1

विनाशक भी स्वचालित है (संकलक उन्हें * आभासी * नहीं बनायेगा, लेकिन यह एक और मुद्दा है)। – visitor

5

अंगूठे का सामान्य नियम कहता है: यदि आपको उनमें से एक की आवश्यकता है, तो आपको उन सभी की आवश्यकता है।

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

+0

कहने के बजाय, "सभी वर्गों को उनकी आवश्यकता नहीं है," यह कहना अधिक सटीक नहीं होगा कि "डिफ़ॉल्ट प्रतिलिपि कन्स्ट्रक्टर को बनाए रखना, विनाशक और असाइनमेंट ऑपरेटर ठीक रहेगा।" (यानी, आपको अपने स्वयं के कार्यान्वयन के साथ डिफ़ॉल्ट को ओवरराइड करने की आवश्यकता नहीं होगी।) – DavidRR

4

डिफ़ॉल्ट प्रतिलिपि कन्स्ट्रक्टर वैक्टर की प्रतिलिपि बनायेगा यदि इसे मूल्य द्वारा घोषित किया जाता है। सावधान रहें यदि आपने अपने वेक्टर में पॉइंटर्स संग्रहीत किए हैं, ऐसे मामले में, आपको स्मृति लीक या एकाधिक डिलीट से बचने के लिए प्रतिलिपि/असाइनमेंट/विनाश के लिए विशिष्ट व्यवहार प्रदान करने की आवश्यकता है।

1

उन कंटेनर को "प्रतिलिपि बनाने योग्य" तत्व की आवश्यकता होगी, और यदि आप कॉपी कन्स्ट्रक्टर की आपूर्ति नहीं करते हैं, तो यह आपके वर्ग के सदस्यों (उथले प्रतिलिपि) से घटाकर आपकी कक्षा के डिफ़ॉल्ट प्रति कन्स्ट्रक्टर को कॉल करेगा।

डिफ़ॉल्ट प्रतिलिपि निर्माता के बारे में आसान स्पष्टीकरण यहाँ है: http://www.fredosaurus.com/notes-cpp/oop-condestructors/copyconstructors.html

यह नाशक के साथ ऐसा होता है तो कंटेनर (यदि आप एक प्रदान करता है नहीं है अपने नाशक या अपने डिफ़ॉल्ट वर्ग नाशक का उपयोग करने की जरूरत है यानी यह होगा। यदि आप अपने विनाशक को निजी के रूप में घोषित करते हैं तो काम नहीं करें)

+0

आपूर्ति किए गए लिंक पर जानकारी बहुत उपयोगी पाया। – DavidRR

0

जब भी आपके पास ऐसी कक्षा होती है जिसके लिए गहरी प्रतियां की आवश्यकता होती है, तो आपको उन्हें परिभाषित करना चाहिए।

विशेष रूप से, किसी भी वर्ग है जो संकेत या संदर्भ शामिल हैं उन्हें रूप में इस तरह शामिल करना चाहिए:

class foo { 
private: 
    int a,b; 
    bar *c; 
} 

Subjectively, मैं हमेशा कहते थे, उन्हें परिभाषित संकलक उत्पन्न संस्करण द्वारा प्रदान की डिफ़ॉल्ट व्यवहार के रूप में क्या नहीं हो सकता है आप उम्मीद/चाहते हैं।

+1

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

+0

@ विज़िटर: लिलबर्न के उत्तर को देखें - यह मूल रूप से वही है लेकिन इसके कारणों में अधिक विस्तृत - विषयपरक रूप से, मुझे लगता है कि वह पैसे पर सही है। –

+0

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

0

स्ट्रिंग या वैक्टर के लिए नहीं, क्योंकि छोटे कन्स्ट्रक्टर/विनाशक आदि ठीक काम करेंगे।

यदि आपकी कक्षा में अन्य डेटा के पॉइंटर्स हैं और उन्हें गहरी प्रतियां चाहिए, या यदि आपकी कक्षा में कोई संसाधन है जिसे हटाया जाना है या किसी विशेष तरीके से कॉपी करना है।

2

नहीं, लेकिन कई कारण हैं कि आपको संकलक को इन कार्यों को स्वचालित रूप से उत्पन्न करने की अनुमति क्यों नहीं देनी चाहिए।

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

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

class myClass { 
    void doSomething(const bigDataContainer data); // not should be passed by reference 
} 

लिखता है तो उन्हें एक कंपाइलर त्रुटि मिल जाएगी। हमारा अनुभव यह है कि एक स्पष्ट बनें() या क्लोन() विधि बहुत कम त्रुटि प्रवण है।

तो सभी में ऑटो उत्पन्न जेनरेटर फ़ंक्शंस से बचने के कई कारण हैं।

+0

'नोट' नहीं होना चाहिए? – Bill

+1

"यह सुनिश्चित करने की आदत में आ जाओ कि जब आप कक्षा बदलते हैं तो उन्हें बनाए रखा जाता है"। यह एक अनावश्यक रखरखाव दुःस्वप्न है। – fredoverflow

+0

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

2

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

क्या मेरी कक्षा का कोई संसाधन है?

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

क्या कोई मेरी कक्षा से प्राप्त कर सकता है?

बेस क्लास को विनाशक की आवश्यकता है। Herb Sutter उन्हें या तो public और virtual (सबसे आम मामला) या protected और गैर-वर्चुअल बनाने की अनुशंसा करता है, जो आप उनके साथ करना चाहते हैं। कंपाइलर से उत्पन्न विनाशक सार्वजनिक और गैर-वर्चुअल है, इसलिए आपको अपना खुद का लिखना होगा, भले ही इसमें कोई कोड न हो। (नोट: इस संकेत नहीं करता आप एक प्रति निर्माता या असाइनमेंट ऑपरेटर लिखने की।)

मैं अपने वर्ग की वस्तुओं को कॉपी से एक उपयोगकर्ता को रोकने चाहिए?

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

निष्कर्ष: किसी

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

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

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