ओवरलोड रिज़ॉल्यूशन में C ++ 11-डिलीट किए गए फ़ंक्शन क्यों भाग लेते हैं?


87

ओवरलोड रिज़ॉल्यूशन में C ++ 11 " deleted" फ़ंक्शन क्यों करता है ?
यह क्यों उपयोगी है? या दूसरे शब्दों में, वे पूरी तरह से हटाए जाने के बजाय छिपे क्यों हैं?



जवाबों:


114

= deleteवाक्यविन्यास का आधा उद्देश्य कुछ मापदंडों के साथ लोगों को कुछ कार्यों को कॉल करने से रोकने में सक्षम होना है। यह मुख्य रूप से कुछ विशिष्ट परिदृश्यों में निहित रूपांतरणों को रोकने के लिए है। किसी विशेष अधिभार को रोकने के लिए, इसे अधिभार संकल्प में भाग लेना होगा।

आपके द्वारा दिया गया उत्तर आपको एक आदर्श उदाहरण देता है:

struct onlydouble {
  onlydouble(std::intmax_t) = delete;
  onlydouble(double);
};

यदि deleteफ़ंक्शन को पूरी तरह से हटा दिया जाता है, तो यह = deleteसिंटैक्स को इसके बराबर बना देगा :

struct onlydouble2 {
  onlydouble2(double);
};

आप ऐसा कर सकते हैं:

onlydouble2 val(20);

यह कानूनी C ++ है। कंपाइलर सभी निर्माणकर्ताओं को देखेगा; उनमें से कोई भी सीधे पूर्णांक प्रकार नहीं लेता है। लेकिन उनमें से एक अंतर्निहित रूपांतरण के बाद इसे ले सकता है। तो यह है कि फोन करेंगे।

onlydouble val(20);

यह कानूनी C ++ नहीं है। कंपाइलर deleteडी सहित सभी निर्माणकर्ताओं को देखेगा । यह एक सटीक मैच देखेगा, के माध्यम से std::intmax_t(जो किसी भी पूर्णांक शाब्दिक से मेल खाएगा)। तो संकलक इसे चुन लेंगे और फिर तुरंत एक त्रुटि जारी करेंगे, क्योंकि यह एक deleteडी फ़ंक्शन का चयन करता है।

= deleteइसका मतलब है "मैं यह मना करता हूं," केवल नहीं, "यह मौजूद नहीं है।" यह ज्यादा मजबूत बयान है।

मैं पूछ रहा था कि C ++ मानक क्यों कहता है = हटाएँ का अर्थ है "मैं इसे मना करता हूं" के बजाय "यह मौजूद नहीं है"

ऐसा इसलिए है क्योंकि हमें यह कहने के लिए विशेष व्याकरण की आवश्यकता नहीं है "यह मौजूद नहीं है।" हम इस प्रश्न में विशेष रूप से "इस" की घोषणा नहीं करते हैं। "मैं इसे मना करता हूं" एक निर्माण का प्रतिनिधित्व करता है जिसे विशेष व्याकरण के बिना प्राप्त नहीं किया जा सकता है। इसलिए हमें "मैं इसे मना करता हूं" कहने के लिए विशेष व्याकरण मिलता है, दूसरी बात नहीं।

एकमात्र कार्यक्षमता जो आपके पास स्पष्ट है "यह मौजूद नहीं है" व्याकरण होगा किसी को बाद में इसे अस्तित्व में घोषित करने से रोकने के लिए होगा। और यह सिर्फ इतना उपयोगी नहीं है कि इसके अपने व्याकरण की आवश्यकता हो।

अन्यथा यह घोषित करने का कोई तरीका नहीं है कि प्रतिलिपि निर्माता मौजूद नहीं है, और इसके अस्तित्व के कारण निरर्थक अस्पष्टताएं हो सकती हैं।

कॉपी कंस्ट्रक्टर एक विशेष सदस्य फ़ंक्शन है। हर क्लास में हमेशा कॉपी कंस्ट्रक्टर होता है। जैसे उनके पास हमेशा कॉपी असाइनमेंट ऑपरेटर, मूव कंस्ट्रक्टर आदि होते हैं।

ये कार्य मौजूद हैं; सवाल केवल यह है कि क्या उन्हें कॉल करना कानूनी है। यदि आपने यह कहने की कोशिश की है कि = deleteइसका मतलब है कि वे मौजूद नहीं थे, तो विनिर्देश को यह बताना होगा कि फ़ंक्शन के मौजूद न होने का क्या अर्थ है। यह एक अवधारणा नहीं है जिसे विनिर्देशन संभालता है।

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

हर मामले में, या तो पहचानकर्ता के माध्यम से घोषित एक फ़ंक्शन है, या एक कंस्ट्रक्टर / विध्वंसक (यह भी पहचानकर्ता के माध्यम से घोषित किया गया है, बस एक प्रकार की पहचानकर्ता)। संचालक ओवरलोडिंग पहचानकर्ता को सिंटैक्टिक चीनी के पीछे छिपा देता है, लेकिन यह अभी भी है।

C ++ विनिर्देशन "मौजूद नहीं है" फ़ंक्शन की अवधारणा को संभाल नहीं सकता है। यह एक अधिभार बेमेल को संभाल सकता है। यह एक अधिभार अस्पष्टता को संभाल सकता है। लेकिन यह पता नहीं है कि वहाँ क्या नहीं है। तो = deleteकम उपयोगी के बजाय "इस कॉल को विफल करने का प्रयास" के रूप में अधिक उपयोगी के रूप में परिभाषित किया गया है "दिखावा मैंने इस लाइन को कभी नहीं लिखा।"

और फिर से, पहले भाग को फिर से पढ़ें। आप ऐसा नहीं कर सकते "फ़ंक्शन मौजूद नहीं है।" इसका एक और कारण है कि इसे इस तरह परिभाषित किया गया है: क्योंकि = deleteसिंटैक्स के मुख्य उपयोग मामलों में से एक उपयोगकर्ता को कुछ पैरामीटर प्रकारों का उपयोग करने के लिए, स्पष्ट रूप से और आगे के लिए मजबूर करने में सक्षम होना है। मूल रूप से, अंतर्निहित प्रकार रूपांतरणों को विफल करने के लिए।

आपका सुझाव ऐसा नहीं होगा।


1
@ मेहरदाद: यदि आपको इस बारे में अधिक स्पष्टीकरण की आवश्यकता है कि क्यों = हटाना आपके इच्छित तरीके से काम नहीं करता है, तो आपको लगता है कि आपके द्वारा हटाए गए सटीक शब्दार्थों पर अधिक स्पष्ट होना चाहिए। क्या यह दिखावा होना चाहिए "मैंने यह पंक्ति कभी नहीं लिखी?" या यह कुछ और होना चाहिए?
निकोल बोलस

1
नहीं, मेरा मतलब है कि मेरा = deleteमतलब है "यह सदस्य मौजूद नहीं है", जिसका अर्थ है कि यह अधिभार संकल्प में भाग नहीं ले सकता है।
user541686

6
@Mehrdad: और अपने मूल बिंदु है, जिसके कारण मैं उसे पोस्ट करने के लिए वापस चला जाता है कि: यदि = deleteमतलब था "इस सदस्य मौजूद नहीं है", तो पहला उदाहरण मैं पोस्ट करने के लिए पूर्णांकों गुजर से लोगों को रोकने के लिए सक्षम नहीं होगा onlydoubleके निर्माता , क्योंकि जो onlydoubleअधिभार हटा दिया गया है वह मौजूद नहीं होगा । यह ओवरलोड रिज़ॉल्यूशन में भाग नहीं लेगा, और इसलिए यह आपको पूर्णांक पास करने से नहीं रोकेगा। जो = deleteवाक्य रचना के बिंदु का आधा है : कहने में सक्षम होने के लिए, "आप एक्स को इस समारोह में नहीं दे सकते।"
निकोल बोलस

3
@ मेहरदाद: उस तर्क से, आपको इसकी आवश्यकता क्यों है =delete? आखिरकार, हम एक ही काम करके "गैर-प्रतिलिपि योग्य" कह सकते हैं: कॉपी कंस्ट्रक्टर / असाइनमेंट को निजी घोषित करना। इसके अलावा, ध्यान दें कि कुछ निजी घोषित करना इसे अचूक नहीं बनाता है; वर्ग के भीतर कोड अभी भी इसे कॉल कर सकता है। इसलिए यह वैसा नहीं है = delete। नहीं, = deleteवाक्य-विन्यास हमें कुछ ऐसा करने की अनुमति देता है जो बहुत अधिक स्पष्ट और उचित तरीके से पहले बहुत असुविधाजनक और असंवेदनशील था।
निकोल बोलस

2
@ मेहरदाद: क्योंकि उत्तरार्द्ध संभव है : इसे "इसे घोषित न करना" कहा जाता है। तो यह मौजूद नहीं होगा। जैसे कि हमें निजी दुर्व्यवहार करने के बजाय एक अधिभार को छिपाने के लिए वाक्यविन्यास की आवश्यकता क्यों है ... क्या आप वास्तव में पूछ रहे हैं कि हमारे पास समान प्रभाव प्राप्त करने के लिए किसी अन्य सुविधा का दुरुपयोग करने के बजाय स्पष्ट रूप से कुछ करने का साधन क्यों होना चाहिए ? यह किसी को भी कोड को पढ़ने के लिए स्पष्ट है कि क्या चल रहा है। यह कोड को उपयोगकर्ता के लिए अधिक आसानी से समझने योग्य बनाता है और वर्कअराउंड में समस्याओं को ठीक करते हुए लिखना आसान बनाता है। हमें या तो लंबोदर की जरूरत नहीं है
निकोल बोलस

10

C ++ वर्किंग ड्राफ्ट 2012-11-02 इस नियम के पीछे एक तर्क प्रदान नहीं करता है, बस कुछ उदाहरण

8.4.3 हटाए गए परिभाषाएं [dcl.fct.def.delete]
...
3 [ उदाहरण : एक गैर-डिफ़ॉल्ट आरंभीकरण और गैर-अभिन्न प्रारंभ के साथ लागू कर सकता है

struct onlydouble {  
  onlydouble() = delete; // OK, but redundant  
  onlydouble(std::intmax_t) = delete;  
  onlydouble(double);  
};  

- अंतिम उदाहरण ]
[ उदाहरण : कोई भी उस वर्ग के लिए उपयोगकर्ता-घोषित ऑपरेटर नए की हटाए गए परिभाषाओं का उपयोग करके कुछ नए अभिव्यक्तियों में एक वर्ग के उपयोग को रोक सकता है।

struct sometype {  
  void *operator new(std::size_t) = delete;  
  void *operator new[](std::size_t) = delete;  
};  
sometype *p = new sometype; // error, deleted class operator new  
sometype *q = new sometype[3]; // error, deleted class operator new[]  

- अंतिम उदाहरण ]
[ उदाहरण : कोई व्यक्ति कॉपी कंस्ट्रक्टर और कॉपी असाइनमेंट ऑपरेटर की हटाए गए परिभाषाओं का उपयोग करके, और फिर मूव कंस्ट्रक्टर और मूव असाइनमेंट ऑपरेटर की डिफॉल्टेड परिभाषाएं प्रदान करके, एक वर्ग को बिना माप के, यानी केवल मूवमेंट बना सकता है।

struct moveonly {  
  moveonly() = default;  
  moveonly(const moveonly&) = delete;  
  moveonly(moveonly&&) = default;  
  moveonly& operator=(const moveonly&) = delete;  
  moveonly& operator=(moveonly&&) = default;  
  ~moveonly() = default;  
};  
moveonly *p;  
moveonly q(*p); // error, deleted copy constructor  

- अंतिम उदाहरण ]


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