सवाल डिफ़ॉल्ट वर्ग कन्स्ट्रक्टर को हटाने का क्या मतलब है?


मैं अपनी सीपीपी परीक्षा की तैयारी कर रहा हूं और सवाल यह है कि: क्या आप डिफॉल्ट क्लास कन्स्ट्रक्टर को हटा सकते हैं और यदि हां, तो ऐसा करने का क्या कारण होगा? ठीक है, तो जाहिर है आप इसे कर सकते हैं:

class MyClass 
{ 
  public: 
    MyClass() = delete; 
};

लेकिन मुझे समझ में नहीं आता कि आप ऐसा क्यों करेंगे?


44
2018-02-07 13:06


मूल


@ डेरेक जॉनसन: इस बारे में क्या: stackoverflow.com/q/13654927/27678 - AndyG
@ acraig5075 यदि आप एक और कन्स्ट्रक्टर प्रदान करते हैं तो डिफ़ॉल्ट कन्स्ट्रक्टर उत्पन्न नहीं होता है, इसलिए इसे हटाने की कोई आवश्यकता नहीं है। - Richard Critten
@AndyG ईमानदारी से अगर आप इसके माध्यम से पढ़ते हैं तो यह वास्तव में इस प्रश्न का उत्तर नहीं देता है। किसी की टिप्पणी से: "मैं ईमानदारी से यह नहीं समझता कि यह मुख्य प्रश्न का उत्तर कैसे देता है। शीर्षक में प्रश्न और ओपी का पहला प्रश्न यह था कि: मैं कब अपने कन्स्ट्रक्टर को स्पष्ट रूप से हटाना चाहूंगा?" - Derek Johnson
@ acraig5075 आपको टिप्पणी फ़ील्ड में सवालों का जवाब नहीं देना चाहिए। - pipe


जवाब:


निम्नलिखित वर्ग पर विचार करें:

struct Foo {
    int i;
};

यह वर्ग एक समग्र है, और आप इन तीनों परिभाषाओं के साथ एक उदाहरण बना सकते हैं:

int main() {
    Foo f1;     // i uninitialized
    Foo f2{};   // i initialized to zero
    Foo f3{42}; // i initialized to 42
}

अब, मान लें कि आपको अनियमित मान और अनिर्धारित व्यवहार पसंद नहीं है जो वे पैदा कर सकते हैं। आप के डिफ़ॉल्ट कन्स्ट्रक्टर को हटा सकते हैं Foo:

struct Foo {
    Foo() = delete;
    int i;
};

Foo अभी भी एक समग्र है, लेकिन केवल बाद की दो परिभाषा मान्य हैं - पहला अब संकलन-समय त्रुटि है।


69
2018-02-07 13:17



या इसके बजाय, बस करो struct Foo { int i = 0; };। - T.C.
@ T.C। सही है, लेकिन मैं काउंटरपॉइंट बढ़ाता हूं कि यह उदाहरण कम से कम है, और अधिक विस्तृत परिस्थितियां हो सकती हैं जहां यह आसान हो सकती है। हालांकि, मैं खुद के साथ नहीं आ सकता। - Machinarius
@ T.C। Foo तब कुल नहीं है; यह प्रति जारीकर्ता नहीं है, लेकिन हम इसे स्पष्ट करना चाहते हैं। (नोटा: केवल सी ++ 11 और सी ++ 14 के लिए) - YSC
@YSC केवल सी ++ 11 के लिए, आपका मतलब है। - T.C.
@ T.C। हो मैं अपने पीडीएफ में मिश्रित हो गया। हाँ आप सही हैं, केवल सी ++ 11। - YSC


डिफ़ॉल्ट कन्स्ट्रक्टर को हटाने के कुछ कारण हैं।

  1. कक्षा पूरी तरह स्थिर है, और आप नहीं चाहते हैं कि उपयोगकर्ता केवल स्थिर विधियों / सदस्यों के साथ कक्षा को तुरंत चालू करें। ऐसी कक्षा का एक उदाहरण ऐसा हो सकता है जो नए वर्ग बनाने के लिए केवल स्थिर तरीकों का उपयोग करके कारखाने के डिजाइन पैटर्न को लागू करता है।
  2. क्लास के लिए डिफॉल्ट कन्स्ट्रक्टर होने के लिए यह समझ में नहीं आता है (चूंकि इसे पैरामीटर की आवश्यकता होती है / कोई डिफ़ॉल्ट मान नहीं है जो वर्ग के लिए समझ में आता है)। इस मामले में, = delete एक स्टाइल चीज है, क्योंकि @ होलीब्लैक कैट ने कहा, लेकिन यह क्लाइंट कोड को बताकर आपके इरादे को स्पष्ट करता है केवल पैरामीटर के साथ निर्माता को बुलाओ।
  3. आप एक समग्र वर्ग के लिए प्रारंभिक डेटा नहीं चाहते हैं।

यदि दूसरा बयान अस्पष्ट था, तो निम्न उदाहरण पर विचार करें:

class A
{
public:
   //A() = delete; 
   A(int, int) {};
};

यदि आपने अभी डिफ़ॉल्ट कन्स्ट्रक्टर को कॉल करने का प्रयास किया है, तो आपको एक त्रुटि मिलेगी जो कुछ ऐसा दिखाई देगी (जीसीसी 7.2):

त्रुटि: 'ए :: ए ()' पर कॉल के लिए कोई मिलान करने वाला फ़ंक्शन नहीं

हालांकि, अगर आपने लाइन को असम्बद्ध किया है = delete, तो आपको निम्नलिखित मिलेंगे:

त्रुटि: हटाए गए फ़ंक्शन 'ए :: ए ()' का उपयोग

यह स्पष्ट रूप से स्पष्ट करता है कि कोई अन्य त्रुटि की तुलना में हटाए गए कन्स्ट्रक्टर का उपयोग करने का प्रयास कर रहा है, जो कुछ हद तक अस्पष्ट है।


43
2018-02-07 13:13



दूसरे मामले में यह स्वचालित रूप से हटा दिया जाएगा, तो = delete एक शैली की बात होगी। - HolyBlackCat
@Quentin शायद केवल स्थिर सदस्यों के साथ एक वर्ग टेम्पलेट हो सकता है। - aschepler
@aschepler मेला पर्याप्त है। हालांकि नामस्थान टेम्पलेट शांत हो जाएगा। - Quentin
@ होलीब्लैक कैट नहीं ... यह होगा पहले से न सोचा, नहीं हटाए गए। एक सूक्ष्म लेकिन कभी-कभी महत्वपूर्ण भेद। व्यावहारिक रूप से बोलते हुए, पूर्व का उपयोग करने का प्रयास "त्रुटि में कोई मिलान करने वाला कन्स्ट्रक्टर ..." जैसी त्रुटि का कारण बनता है, जबकि बाद में "डिफ़ॉल्ट कन्स्ट्रक्टर कॉल में हटा दिया गया है ..." की त्रुटि होगी (मैं सटीक जांचने के लिए बहुत आलसी हूं यद्यपि शब्द, जो संकलक पर निर्भर करता है।) - Arne Vogel
@HolyBlackCat हटाए गए func। अधिभार संकल्प में भाग लेता है। जैसे साथ में X(const X&) उपयोगकर्ता द्वारा घोषित, कोई कदम c'tor निहित घोषित किया गया है, लेकिन X(std::move(anotherX)) निकटतम मैच के रूप में कॉपी c'tor का चयन, अभी भी काम करेंगे। लेकिन यदि चाल ctor हटा दिया गया है, तो यह कोड खराब गठित हो जाता है। इसके अलावा, यदि आपके पास एक वैरिएडिक कैटर है उदा। X(Args&&...), इसका उपयोग ऑब्जेक्ट w / o तर्कों को बनाने के लिए किया जा सकता है, लेकिन हटाए जाने पर नहीं X()। संदर्भ - Arne Vogel


एकाधिक डिफ़ॉल्ट विकल्प

किसी वर्ग के डिफ़ॉल्ट कन्स्ट्रक्टर को हटाने का एक अच्छा विचार है जब डिफ़ॉल्ट या अनियंत्रित स्थिति के लिए कई विकल्प होते हैं। उदाहरण के लिए, मान लीजिए मेरे पास एक कक्षा है,

template<typename F>
class Polynomial;

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


कोई डिफ़ॉल्ट विकल्प नहीं

दूसरा उल्लेखनीय मामला तब होता है जब कई डिफ़ॉल्ट राज्य होने की बजाय समझ में आता है, हमारे पास कोई नहीं है। उदाहरण के लिए, मान लीजिए कि हमारे पास एक वर्ग है जो प्रतिनिधित्व करता है विविध या सतह।

तब क्या है Manifold()? यह एक खाली जगह है, कुछ भी नहीं, कोई सतह नहीं, दूरी या मीट्रिक की कोई धारणा नहीं है। लेकिन फिर इसे कई गुना के रूप में सोचने का अर्थ नहीं है, बल्कि शायद एक स्थलीय स्थान की तरह कुछ और सामान्य है।

इसलिए, इस मामले में, मैं डिफ़ॉल्ट कन्स्ट्रक्टर को भी हटाने का विकल्प चुनूंगा।


5
2018-02-07 20:54





कभी-कभी कक्षाएं तत्काल होने का इरादा नहीं रखती हैं।

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

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


5
2018-02-07 21:39