मीनिंग ऑफ फंक्शन डिक्लेरेशन के बाद डिलीट


242
class my_class
{
    ...
    my_class(my_class const &) = delete;
    ...
};

= deleteउस संदर्भ में क्या मतलब है?

क्या कोई अन्य "संशोधक" (अन्य की तुलना में ) = 0और हैं = delete?


23
@Blindy यह C ++ 0x में मानक होगा, यानी जल्द ही।
कोनराड रुडोल्फ

1
मैं सही खड़ा हूं, मुझे यह C ++ 0x सुविधा याद आ गई थी। मैं सोच रहा था कि यह #defineएक ला क्यूटी था जिसने 0 का मूल्यांकन किया और फिर एक छिपे हुए फ़ंक्शन या कुछ को घोषित किया।
ब्लाइंडी

मैंने 'अक्षम' कीवर्ड का स्मरण किया है जिसका अर्थ समान या कुछ इसी तरह है। क्या मैं इसकी कल्पना कर रहा हूं? या उनके बीच कोई सूक्ष्म अंतर है?
स्टीवर्ट

जवाबों:


201

एक फ़ंक्शन को हटाना C ++ 11 सुविधा है :

"नकल पर रोक" का सामान्य मुहावरा अब सीधे व्यक्त किया जा सकता है:

class X {
    // ...
    X& operator=(const X&) = delete;  // Disallow copying
    X(const X&) = delete;
};

[...]

किसी भी फ़ंक्शन के लिए "हटाएं" तंत्र का उपयोग किया जा सकता है। उदाहरण के लिए, हम इस तरह एक अवांछित रूपांतरण को समाप्त कर सकते हैं:

struct Z {
    // ...

    Z(long long);     // can initialize with an long long         
    Z(long) = delete; // but not anything less
};

3
सिर्फ "कॉपी-प्रति-संचालक और ऑपरेटर =" निजी बनाने के लिए "नकल पर रोक लगाने" की पारंपरिक विधि नहीं है? यह थोड़ा और आगे जाता है और संकलक को निर्देश देता है कि वह फंक्शन्स को उत्पन्न न करे। यदि वे दोनों निजी और = नष्ट कर रहे हैं, तो दोहरे रूप से निषिद्ध है?
Reb.Cabin

8
@ रीब, =deleteविधि को संदर्भों से भी दुर्गम बनाता है जो privateतरीकों (अर्थात कक्षा और उसके दोस्तों के भीतर) को देख सकता है। जब आप कोड पढ़ रहे हों तो यह किसी भी अनिश्चितता को हटा देता है। @Prasoon, दूसरा उदाहरण अभी भी केवल निर्माणकर्ताओं को हटा रहा है - operator long ()उदाहरण के लिए हटाए गए को देखना अच्छा होगा ।
टोबी स्पाइट

2
@ Reb.Cabin का उपयोग करना या इसी तरह के अन्य तंत्रों की = deleteतुलना में बेहतर है privateक्योंकि आमतौर पर आप चाहते हैं कि निषिद्ध कार्य को दृष्टिगत रूप से घोषित किया जाए और अधिभार संकल्प आदि के लिए विचार किया जाए, ताकि यह जल्द से जल्द विफल हो जाए और उपयोगकर्ता को स्पष्ट त्रुटि प्रदान कर सके। कोई भी समाधान जिसमें घोषणा को "छिपाना" शामिल है, इस प्रभाव को कम करता है।
लेउशेंको

1
क्या कॉपी कंस्ट्रक्टर को सार्वजनिक करने और डिलीट कीवर्ड को लागू करने का कोई विशेष कारण है। कंस्ट्रक्टर को निजी क्यों न छोड़ें और कीवर्ड क्यों लागू करें?
दोहन ​​जो

81
  1. = 0इसका मतलब है कि एक फ़ंक्शन शुद्ध आभासी है और आप इस वर्ग से किसी ऑब्जेक्ट को तुरंत नहीं कर सकते। आपको इसे प्राप्त करने और इस पद्धति को लागू करने की आवश्यकता है
  2. = deleteइसका मतलब है कि कंपाइलर आपके लिए उन कंस्ट्रक्टर्स को जेनरेट नहीं करेगा। AFAIK को केवल कॉपी कंस्ट्रक्टर और असाइनमेंट ऑपरेटर की अनुमति है। लेकिन मैं आगामी मानक पर बहुत अच्छा नहीं हूं।

4
=deleteवाक्य रचना के कुछ अन्य उपयोग हैं । उदाहरण के लिए आप इसका उपयोग स्पष्ट रूप से कुछ प्रकार के निहितार्थ रूपांतरणों को हटाने के लिए कर सकते हैं जो कॉल के साथ हो सकते हैं। इसके लिए आप बस ओवरलोड कार्यों को हटा दें। अधिक जानकारी के लिए C ++ 0x पर विकिपीडिया पृष्ठ देखें।
13

जैसे ही मुझे कुछ मिलेगा मैं वह करूंगा। यह समय लगता है कि यह c ++
0X

हाँ, C ++ 0x चट्टानें। मैं GCC 4.5+ के अधिक सामान्य होने की प्रतीक्षा नहीं कर सकता, इसलिए मैं लैम्ब्डा का उपयोग शुरू कर सकता हूं।
LiKao

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

28

C ++ प्रोग्रामिंग लैंग्वेज [4th Edition] का यह अंश - Bjarne Stroustrup पुस्तक के पीछे वास्तविक उद्देश्य के बारे में बात करती है =delete:

3.3.4 दमन संचालन

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

class Shape {
public:
  Shape(const Shape&) =delete; // no copy operations
  Shape& operator=(const Shape&) =delete;

  Shape(Shape&&) =delete; // no move operations
  Shape& operator=(Shape&&) =delete;
  ˜Shape();
    // ...
};

अब कंपाइलर द्वारा शेप को कॉपी करने का प्रयास पकड़ा जाएगा।

=deleteतंत्र कि है आम हो गए हैं, यह किसी भी आपरेशन को दबाने के लिए इस्तेमाल किया जा सकता


10

क्या कोई अन्य "संशोधक" (अन्य की तुलना में ) = 0और हैं = delete?

चूंकि यह प्रतीत होता है कि किसी और ने इस सवाल का जवाब नहीं दिया, इसलिए मुझे यह उल्लेख करना चाहिए कि वहाँ भी है =default

https://docs.microsoft.com/en-us/cpp/cpp/explicitly-defaulted-and-deleted-functions#explicitly-defaulted-functions


1
याह, मुझे इसकी तलाश थी।
कोडर

5

मैंने जिन कोडिंग मानकों के साथ काम किया है उनमें से अधिकांश वर्ग घोषणाओं के लिए निम्नलिखित हैं।

//  coding standard: disallow when not used
T(void)                  = delete; // default ctor    (1)
~T(void)                 = delete; // default dtor    (2)
T(const T&)              = delete; // copy ctor       (3)
T(const T&&)             = delete; // move ctor       (4)
T& operator= (const T&)  = delete; // copy assignment (5)
T& operator= (const T&&) = delete; // move assignment (6)

यदि आप इन 6 में से किसी का भी उपयोग करते हैं, तो आप संबंधित लाइन के बारे में टिप्पणी करते हैं।

उदाहरण: वर्ग FizzBus को केवल डोर की आवश्यकता होती है, और इस प्रकार अन्य 5 का उपयोग नहीं करते हैं।

//  coding standard: disallow when not used
FizzBuzz(void)                         = delete; // default ctor (1)
// ~FizzBuzz(void);                              // dtor         (2)
FizzBuzz(const FizzBuzz&)              = delete; // copy ctor    (3)
FizzBuzz& operator= (const FizzBuzz&)  = delete; // copy assig   (4)
FizzBuzz(const FizzBuzz&&)             = delete; // move ctor    (5)
FizzBuzz& operator= (const FizzBuzz&&) = delete; // move assign  (6)

हम यहां केवल 1 टिप्पणी करते हैं, और इसके कार्यान्वयन को स्थापित करते हैं जहां (शायद जहां कोडिंग मानक का सुझाव है)। अन्य 5 (6 में से) हटाए जाने के साथ अस्वीकृत हैं।

आप अलग-अलग आकार के मूल्यों के निहित प्रचारों को हटाने के लिए '= हटाएं' का भी उपयोग कर सकते हैं ... उदाहरण

// disallow implicit promotions 
template <class T> operator T(void)              = delete;
template <class T> Vuint64& operator=  (const T) = delete;
template <class T> Vuint64& operator|= (const T) = delete;
template <class T> Vuint64& operator&= (const T) = delete;

3

= deleteC ++ 11 में एक फीचर परिचय है। के रूप में =deleteयह उस फ़ंक्शन को कॉल करने की अनुमति नहीं देगा।

विस्तार से।

एक कक्षा में मान लीजिए।

Class ABC{
 Int d;
 Public:
  ABC& operator= (const ABC& obj) =delete
  {

  }
};

इस फ़ंक्शन को obj असाइनमेंट के लिए कॉल करते समय इसे अनुमति नहीं दी जाएगी। मीन्स असाइनमेंट ऑपरेटर एक ऑब्जेक्ट से दूसरे में कॉपी करने के लिए प्रतिबंधित करने जा रहा है।


2

नया सी ++ 0x मानक। कृपया N3242 वर्किंग ड्राफ्ट में सेक्शन 8.4.3 देखें


वाह, यह मसौदा पुराना है। यहाँ नवीनतम (3 अप्रैल 2011 के अनुसार) है: open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
टोनीके

धन्यवाद और लिंक को अपडेट किया। वर्तमान ड्राफ्ट प्राप्त करने के लिए बहुत उपयोगी है। पुराने ड्राफ्ट में भी संदर्भित खंड / सामग्री सही थी, इसलिए मुझे डाउन वोट की समझ नहीं है।
डबंडे

1

हटाए गए फ़ंक्शन का निहितार्थ है

(मौजूदा उत्तरों के लिए परिशिष्ट)

... और हटाए गए फ़ंक्शन फ़ंक्शन की पहली घोषणा होगी (फ़ंक्शन टेम्प्लेट की स्पष्ट विशेषज्ञता को हटाने के अलावा - विलोपन विशेषज्ञता के पहले घोषणा पर होना चाहिए), जिसका अर्थ है कि आप फ़ंक्शन की घोषणा नहीं कर सकते हैं और बाद में इसे हटा सकते हैं, कहते हैं, अनुवाद इकाई में इसकी परिभाषा स्थानीय है।

उद्धृत करना [dcl.fct.def.delete] / 4 :

हटाए गए फ़ंक्शन का निहितार्थ है। ( नोट: एक परिभाषा नियम ( [basic.def.odr] ) हटाए गए परिभाषाओं पर लागू होता है। - अंतिम नोट ] किसी फ़ंक्शन की हटाए गए परिभाषा फ़ंक्शन फ़ंक्शन की स्पष्ट विशेषज्ञता के लिए फ़ंक्शन की पहली घोषणा होगी या। उस विशेषज्ञता की पहली घोषणा। [उदाहरण:

struct sometype {
  sometype();
};
sometype::sometype() = delete;      // ill-formed; not first declaration

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

हटाए गए परिभाषा के साथ एक प्राथमिक फ़ंक्शन टेम्पलेट विशिष्ट हो सकता है

अंगूठे का एक सामान्य नियम है, विशेष प्रकार के टेम्प्लेट से बचने के लिए, क्योंकि विशेषज्ञ अतिभार के पहले चरण में भाग नहीं लेते हैं, ऐसे कुछ संदर्भ हैं जहां यह उपयोगी हो सकता है। जब एक गैर-अतिभारित का उपयोग कर सभी प्रकार के मिलान के लिए बिना किसी परिभाषा के प्राथमिक फ़ंक्शन टेम्पलेट जो कि एक अन्यथा मिलान-दर-रूपांतरण अधिभार में परिवर्तित नहीं होता है; यानी, गैर-परिभाषित, गैर-अतिभारित प्राथमिक फ़ंक्शन टेम्पलेट के स्पष्ट विशेषज्ञता में केवल सटीक प्रकार के मैचों को लागू करके कई निहितार्थ-रूपांतरण मैचों को हटाने के लिए।

C ++ 11 की डिलीटेड फंक्शन कॉन्सेप्ट से पहले, कोई भी प्राथमिक फ़ंक्शन टेम्प्लेट की परिभाषा को छोड़ कर ऐसा कर सकता था, लेकिन इसने अस्पष्ट अपरिष्कृत संदर्भ त्रुटियां दीं, जो प्राथमिक फ़ंक्शन टेम्प्लेट के लेखक से जानबूझकर कोई अर्थपूर्ण इरादे नहीं देती थीं (जानबूझकर छोड़ा गया ?)। यदि हम इसके बजाय प्राथमिक फ़ंक्शन टेम्पलेट को स्पष्ट रूप से हटाते हैं, तो कोई उपयुक्त स्पष्ट विशेषज्ञता नहीं मिलने की स्थिति में त्रुटि संदेश बहुत अच्छे हो जाते हैं, और यह भी दर्शाता है कि प्राथमिक फ़ंक्शन टेम्पलेट की परिभाषा का चूक / विलोपन जानबूझकर किया गया था।

#include <iostream>
#include <string>

template< typename T >
void use_only_explicit_specializations(T t);

template<>
void use_only_explicit_specializations<int>(int t) {
    std::cout << "int: " << t;
}

int main()
{
    const int num = 42;
    const std::string str = "foo";
    use_only_explicit_specializations(num);  // int: 42
    //use_only_explicit_specializations(str); // undefined reference to `void use_only_explicit_specializations< ...
}

हालाँकि, उपर्युक्त प्राथमिक फ़ंक्शन टेम्प्लेट के लिए एक परिभाषा को छोड़ देने के बजाय, अस्पष्ट अस्पष्ट संदर्भ त्रुटि उत्पन्न होने पर जब कोई स्पष्ट विशेषज्ञता मेल नहीं खाती है, तो प्राथमिक टेम्पलेट परिभाषा को हटाया जा सकता है:

#include <iostream>
#include <string>

template< typename T >
void use_only_explicit_specializations(T t) = delete;

template<>
void use_only_explicit_specializations<int>(int t) {
    std::cout << "int: " << t;
}

int main()
{
    const int num = 42;
    const std::string str = "foo";
    use_only_explicit_specializations(num);  // int: 42
    use_only_explicit_specializations(str);
    /* error: call to deleted function 'use_only_explicit_specializations' 
       note: candidate function [with T = std::__1::basic_string<char>] has 
       been explicitly deleted
       void use_only_explicit_specializations(T t) = delete; */
}

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

हम इस तकनीक का उपयोग क्यों करना चाहते हैं? फिर से, स्पष्ट विशेषज्ञताओं के लिए उपयोगी हो सकता है परोक्ष अंतर्निहित रूपांतरण को हटा दें।

#include <cstdint>
#include <iostream>

void warning_at_best(int8_t num) { 
    std::cout << "I better use -Werror and -pedantic... " << +num << "\n";
}

template< typename T >
void only_for_signed(T t) = delete;

template<>
void only_for_signed<int8_t>(int8_t t) {
    std::cout << "UB safe! 1 byte, " << +t << "\n";
}

template<>
void only_for_signed<int16_t>(int16_t t) {
    std::cout << "UB safe! 2 bytes, " << +t << "\n";
}

int main()
{
    const int8_t a = 42;
    const uint8_t b = 255U;
    const int16_t c = 255;
    const float d = 200.F;

    warning_at_best(a); // 42
    warning_at_best(b); // implementation-defined behaviour, no diagnostic required
    warning_at_best(c); // narrowing, -Wconstant-conversion warning
    warning_at_best(d); // undefined behaviour!

    only_for_signed(a);
    only_for_signed(c);

    //only_for_signed(b);  
    /* error: call to deleted function 'only_for_signed' 
       note: candidate function [with T = unsigned char] 
             has been explicitly deleted
       void only_for_signed(T t) = delete; */

    //only_for_signed(d);
    /* error: call to deleted function 'only_for_signed' 
       note: candidate function [with T = float] 
             has been explicitly deleted
       void only_for_signed(T t) = delete; */
}

0

यह C ++ 0x मानकों में नई बात है, जहां आप विरासत में मिले फंक्शन को डिलीट कर सकते हैं।


11
आप किसी भी फ़ंक्शन को हटा सकते हैं। ईजी void foo(int); template <class T> void foo(T) = delete;सभी निहित रूपांतरणों को रोकता है। केवल intप्रकार के तर्क स्वीकार किए जाते हैं, अन्य सभी एक "हटाए गए" फ़ंक्शन को तुरंत करने का प्रयास करेंगे।
अंकल बीन्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.