2012-02-27 6 views
56

सी ++ 11 में स्पष्ट रूप से हटाए गए सदस्य फ़ंक्शंस के साथ, क्या यह अभी भी एक गैर-लोकप्रिय बेस क्लास से प्राप्त करने के लिए उपयुक्त है?सी ++ 11 में स्पष्ट रूप से हटाए गए सदस्य फ़ंक्शंस के साथ, क्या यह अभी भी एक गैर-लोकप्रिय बेस क्लास से प्राप्त करने के लिए उपयुक्त है?

मैं उस चाल के बारे में बात कर रहा हूं जहां आप निजी रूप से बेस क्लास का उत्तराधिकारी हैं, जिसमें निजी या हटाए गए प्रतिलिपि निर्माता और कॉपी असाइनमेंट (उदा। boost::noncopyable) है।

क्या इस question में अभी भी फायदे हैं जो सी ++ 11 पर लागू होते हैं?


मुझे नहीं लगता कि कुछ लोग दावा करते हैं कि कक्षा + + में गैर-प्रतिलिपि बनाने योग्य वर्ग बनाना आसान है।

सी ++ 03 में:

private: 
    MyClass(const MyClass&) {} 
    MyClass& operator=(const MyClass&) {} 

सी ++ 11 में:

MyClass(const MyClass&) = delete; 
MyClass& operator=(const MyClass&) = delete; 

संपादित करें:

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

+2

आप एक मुहावरे का वर्णन नहीं कर रहे हैं, लेकिन इसके केवल एक कार्यान्वयन। मुहावरे बनी हुई है, और अब लिखना आसान है। –

+0

एक खाली निजी प्रतिलिपि निर्माता और निजी प्रति असाइनमेंट ऑपरेटर लिखने से यह कैसे आसान है? –

+0

'idiom' शब्द का दुरुपयोग से बचने के लिए संपादित किया गया। –

उत्तर

73

खैर, यह:

private: 
    MyClass(const MyClass&) {} 
    MyClass& operator=(const MyClass&) {} 

फिर भी तकनीकी रूप से अनुमति देता है MyClass के सदस्यों और दोस्तों से कॉपी करने के लिए। निश्चित रूप से, उन प्रकारों और कार्यों सैद्धांतिक रूप से आपके नियंत्रण में हैं, लेकिन कक्षा अभी भी कॉपी करने योग्य है। कम से कम boost::noncopyable और = delete, कोई भी कक्षा की प्रतिलिपि बना सकता है।


मैं नहीं क्यों कुछ लोग दावा करते हैं कि यह आसान है सी ++ 11 में एक वर्ग के गैर copyable बनाने के लिए है।

यह "अधिक आसानी से पचाने योग्य" के रूप में इतना आसान नहीं है।

इस पर विचार करें:

class MyClass 
{ 
private: 
    MyClass(const MyClass&) {} 
    MyClass& operator=(const MyClass&) {} 
}; 

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

यह समझने के लिए कि यह प्रतिलिपि को रोकता है, आपको यह समझना होगा कि उन्हें निजी घोषित करके, आप इसे बनाते हैं ताकि गैर-सदस्य/मित्र इसे कॉपी नहीं कर सकें। यह नौसिखिया के लिए तुरंत स्पष्ट नहीं है। न ही त्रुटि संदेश है कि वे इसे कॉपी करने का प्रयास करते समय प्राप्त करेंगे।

अब, सी ++ 11 संस्करण की तुलना:

class MyClass 
{ 
public: 
    MyClass(const MyClass&) = delete; 
    MyClass& operator=(const MyClass&) = delete; 
}; 

क्या यह समझना महत्वपूर्ण है कि इस वर्ग कॉपी नहीं किया जा सकता है लगता है? = delete वाक्यविन्यास का अर्थ समझने से कुछ और नहीं है। सी ++ 11 के सिंटैक्स नियमों को समझाते हुए कोई भी पुस्तक आपको बताएगी कि वह क्या करता है। इस कोड का प्रभाव अनुभवहीन सी ++ उपयोगकर्ता के लिए स्पष्ट है।

इस मुहावरे के बारे में क्या बढ़िया बात यह है कि यह एक मुहावरे बन जाता है क्योंकि यह वास्तव में कहने का सबसे स्पष्ट, सबसे स्पष्ट तरीका है।

यहां तक ​​कि boost::noncopyable को थोड़ा और विचार चाहिए। हां, इसे "noncopyable" कहा जाता है, इसलिए यह स्वयं-दस्तावेज है। लेकिन अगर आपने इसे पहले कभी नहीं देखा है, तो यह सवाल उठाता है। आप ऐसी चीज से क्यों प्राप्त कर रहे हैं जिसे कॉपी नहीं किया जा सकता है? मेरे त्रुटि संदेश boost::noncopyable की कॉपी कन्स्ट्रक्टर के बारे में क्यों बात करते हैं? इत्यादि। फिर, मुहावरे को समझने के लिए अधिक मानसिक प्रयास की आवश्यकता होती है।

+12

+1 मुझे यह पसंद है कि आप कैसे वर्णन करते हैं कि '= delete' लिखना जरूरी नहीं है, लेकिन * पढ़ने के लिए आसान * है। –

+1

मैं सिर्फ यह ध्यान रखना चाहता हूं कि परिभाषित निकाय के बिना निजी सीटीओ और कॉपी असाइनमेंट ऑपरेटर चाल करेंगे। कोई सिर्फ 'MyClass (कॉन्स MyClass &);' रिक्त परिभाषा प्रदान करने के बजाय 'MyClass (const MyClass &) {}' घोषित कर सकता है और इस तरह से कक्षा स्वयं के भीतर गैर-प्रति-रचनात्मक है। हालांकि '= delete' प्रोग्रामर के इरादे स्पष्ट करता है और आत्म-व्याख्यात्मक है। – doc

5

यह अधिक पठनीय है और संकलक को बेहतर त्रुटियां देने की अनुमति देता है।

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

लेकिन वास्तव में, यह केवल एक सुविधा सुविधा है।

25

पहली बात यह है कि के रूप में मेरे सामने दूसरों का कहना है, आप मुहावरा गलत, आप निजी रूप घोषित हो गया और परिभाषित नहीं करते:

class noncopyable { 
    noncopyable(noncopyable const &); 
    noncopyable& operator=(noncopyable const &); 
}; 

कहाँ operator= की वापसी प्रकार मूल रूप से कुछ भी हो सकता है। इस बिंदु पर, यदि आप उस कोड को हेडर में पढ़ते हैं, तो इसका वास्तव में क्या अर्थ है? इसे केवल दोस्तों द्वारा कॉपी किया जा सकता है या इसे कभी कॉपी नहीं किया जा सकता है? ध्यान दें कि यदि आप अपने उदाहरण के रूप में परिभाषा प्रदान करते हैं, तो यह बता रहा है कि मुझे केवल कक्षा के अंदर और दोस्तों द्वारा की प्रतिलिपि बनाई जा सकती है, यह परिभाषा की कमी है जो इसे में अनुवादित करती है, मुझे कॉपी नहीं किया जा सकता है। लेकिन शीर्षलेख में परिभाषा की कमी परिभाषा हर जगह की कमी के लिए समानार्थी नहीं है, क्योंकि इसे सीपीपी फ़ाइल में परिभाषित किया जा सकता है।

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

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

एक अंतिम टिप्पणी के रूप में, सी ++ 11 में सुविधा सिर्फ के बारे में कम कोड या बेहतर के साथ noncopyable लिखने में सक्षम नहीं किया जा रहा है, बल्कि कोड है कि आप उत्पन्न नहीं करना चाहते पैदा करने से संकलक बाधा के बारे में। यह उस सुविधा का सिर्फ एक प्रयोग है।

+3

** आपने एक बहुत ही महत्वपूर्ण बिंदु उठाया है **: खाली निजी कार्यान्वयन स्वयं को वस्तु की प्रतिलिपि बनाने से रोक नहीं देते हैं! बेवकूफ निजी परिभाषाएं प्रदान करने के लिए मुहावरे * नहीं * है। मुहावरे * केवल घोषणाएं * प्रदान करना है। –

+1

@ क्यूबा यह समाधान कुछ मानक-अनुरूप कंपिलरों/लिंकर्स के साथ काम नहीं करता है, क्योंकि उन्हें आवश्यकता होती है कि जब आप सदस्य फ़ंक्शन घोषित करते हैं तो आपको इसे परिभाषित करना होगा। उदाहरण के लिए, ग्रीन हिल्स कंपाइलर/लिंकर आपकी प्रतिलिपि ctor और असाइनमेंट ऑपरेटर के लिए अनुपलब्ध परिभाषाओं के संबंध में एक लिंकर त्रुटि के साथ विफल हो जाएगा, भले ही कोई कोड उनका उपयोग न करे। – ThreeBit

+1

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

10

अंक दूसरों को लाया है के अलावा ...

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

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

2

यहां लोग सिफारिश कर रहे हैं कि आप उन्हें परिभाषित किए बिना सदस्य कार्य घोषित करें। मैं यह इंगित करना चाहता हूं कि ऐसा दृष्टिकोण पोर्टेबल नहीं है। कुछ कंपाइलर्स/लिंकर्स की आवश्यकता होती है कि यदि आप सदस्य फ़ंक्शन घोषित करते हैं तो आपको इसे भी परिभाषित करना होगा, भले ही इसका उपयोग न किया जाए। यदि आप केवल वीसी ++, जीसीसी, क्लैंग का उपयोग कर रहे हैं तो आप इससे दूर हो सकते हैं, लेकिन यदि आप वास्तव में पोर्टेबल कोड लिखने की कोशिश कर रहे हैं तो कुछ अन्य कंपाइलर्स (जैसे ग्रीन हिल्स) असफल हो जाएंगे।

+1

मुझे इस जवाब पर संदेह है। चूंकि कई संकलन इकाइयों में कक्षा के सदस्य कार्यों को परिभाषित करना कानूनी है क्योंकि वास्तव में इस एंटी-फीचर को कार्यान्वित करना मुश्किल होगा। उदाहरण जीसीसी/क्लैंग/आईसीसी के साथ काम करता है? – Praxeolitic

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

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