2009-07-13 15 views
39

डिफ़ॉल्ट विनाशक आभासी विनाशक के रूप में स्वचालित रूप से उत्पन्न किया जा सकता है?डिफ़ॉल्ट विनाशक आभासी विनाशक के रूप में स्वचालित रूप से उत्पन्न किया जा सकता है?

यदि मैं बेस क्लास को परिभाषित करता हूं लेकिन कोई डिफ़ॉल्ट विनाशक नहीं है, तो क्या डिफ़ॉल्ट वर्चुअल विनाशक स्वचालित रूप से जेनरेट किया जाता है?

+0

वैसे, बस सोच रहा है, एक डिफ़ॉल्ट विनाशक क्या है? क्या एक और प्रकार का विनाशक है? – user88637

+4

@ yossi1981: यदि आप कक्षा में विनाशक घोषित नहीं करते हैं, तो संकलक आपके लिए एक सम्मिलित करता है। कुछ असामान्य मामले के बारे में गलत होने के जोखिम पर, यह "डिफ़ॉल्ट विनाशक" वैसा ही है जैसा आपने "~ MyClass() {}" परिभाषित किया था। –

+3

@onebyone: सटीक होना: 'सार्वजनिक: ~ MyClass() {}' - भले ही कक्षा के सदस्य डिफ़ॉल्ट रूप से निजी हों। – MSalters

उत्तर

37

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

क्यों न केवल खाली आभासी विनाशक को परिभाषित करें?

+42

ध्यान दें कि आप 'वर्चुअल ~ फू() = डिफ़ॉल्ट भी कर सकते हैं; [सी ++ 11] (http://en.cppreference.com/w/cpp/language/member_functions#Special_member_functions) के रूप में (यदि कोई है इसे हाल ही में पढ़ना) – CoryKramer

+1

क्या कक्षा में कोई अन्य वर्चुअल फ़ंक्शंस है, तो अतिरिक्त लागत क्या हो सकती है? क्या आप एक उदाहरण दे सकते हैं? – Spencer

+0

@ स्प्परसर: विनाशक को कॉल करने से ऑब्जेक्ट के vtable के माध्यम से रनटाइम पर हल होने के लिए डी-टोर कोड के पते की आवश्यकता होती है। गैर आभासी विनाशकों के लिए कोड का पता संकलन समय पर जाना जाता है। –

1

नहीं। आपको इसे वर्चुअल के रूप में घोषित करने की आवश्यकता है।

8

उरी और माइकल ठीक कह रहे हैं - मैं तो बस जोड़ देंगे कि क्या गुस्सा दिलाना आप घोषित करने और नाशक परिभाषित करने के लिए दो फ़ाइलों को छूने के लिए आ रही है, तो यह पूरी तरह से शीर्षक में एक न्यूनतम एक इनलाइन परिभाषित करने के लिए सब ठीक है:

class MyClass 
{ 
    // define basic destructor right here 
    virtual ~MyClass(){} 

    // but these functions can be defined in a different file 
    void FuncA(); 
    int FuncB(int etc); 
} 
+0

वास्तव में मुझे लगता है कि आप पाएंगे कि जब आप इसे लिंक करेंगे, तो आपको MyClass 'vtable के लिए एक अनिर्धारित संदर्भ प्राप्त होगा। – keraba

+2

यदि आप जीसीसी का उपयोग कर रहे हैं तो आपको केवल "vtable के लिए अपरिभाषित संदर्भ" त्रुटि मिलेगी और आप FuncA और FuncB को गैर-इनलाइन परिभाषित नहीं करते हैं, और यही कारण है कि जीसीसी उचित आवश्यक अनुमति देने के लिए सभी आवश्यक सामग्री को उत्सर्जित करने में विफल रहा है जोड़ने। –

+0

मैं इससे आश्चर्यचकित हूं, इससे लिंकिंग समस्या क्यों होगी? क्या कोई विस्तार कर सकता है? – Uri

9

नहीं, सभी विनाशक डिफ़ॉल्ट रूप से आभासी नहीं हैं।

आप सभी आधार वर्ग

इसके अलावा पर एक आभासी नाशक को परिभाषित करने की आवश्यकता होगी।

The C++ language standard is unusually clear on this topic. When you try to delete a derived class object through a base class pointer and the base class has a non-virtual destructor (as EnemyTarget does), the results are undefined

व्यवहार में, यह आमतौर पर एक अच्छा विचार है अगर आपको लगता है कि किसी को अंततः एक व्युत्पन्न वर्ग बना सकता है एक आभासी नाशक के साथ एक वर्ग को परिभाषित करने के लिए है:

अपनी पुस्तक "प्रभावी सी ++" में स्कॉट Meyers के शब्दों में इसमें से। मैं बस सभी वर्गों को आभासी विनाशक बना देता हूं। हां, इसके साथ जुड़ी एक लागत है, लेकिन इसे वर्चुअल बनाने की लागत अक्सर अधिक नहीं होती है, जो रन-टाइम ओवरहेड के बराबर वजन का वजन नहीं करती है।

मेरा सुझाव है, केवल यह गैर-आभासी बनाओ जब आप पूरी तरह से निश्चित हैं कि आप डिफ़ॉल्ट गैर-आभासी पर भरोसा करने के बजाए इसे इस तरह से चाहते हैं कि संकलक लागू होते हैं। आप असहमत हो सकते हैं, हालांकि (संक्षेप में) मैंने हाल ही में कुछ विरासत कोड पर एक भयंकर स्मृति रिसाव किया था, जहां मैंने जो कुछ किया था, वह कई वर्षों तक मौजूद वर्गों में से एक में std :: वेक्टर जोड़ रहा था। यह पता चला है कि इसके मूल वर्गों में से एक में विनाशक परिभाषित नहीं था (डिफ़ॉल्ट विनाशक खाली, गैर-आभासी है!) और उस बिंदु तक कोई स्मृति लीक होने से पहले इस तरह की कोई स्मृति आवंटित नहीं की जा रही थी। कई दिनों की जांच और समय बाद में बर्बाद हो गया ...

+1

इसलिए यदि मैं स्थिति को सही ढंग से समझता हूं, तो आपके कोड में परिवर्तन करने से पहले आपके पास पहले से ही अपरिभाषित व्यवहार (हालांकि स्मृति रिसाव नहीं था): बेस क्लास पॉइंटर के माध्यम से हटाया जा रहा है, आपकी व्युत्पन्न वस्तु को मूल रूप से नष्ट कर दिया गया है (पहले) । अन्य डेटा सदस्यों (जो विनाश की आवश्यकता होगी) की अनुपस्थिति व्यवहार को परिभाषित नहीं करती है। तो आपकी जांच बर्बाद नहीं हुई थी ... –

9

हां, एक आभासी विनाशक के साथ बेस क्लास से विरासत में प्राप्त करके। इस मामले में, आप पहले से ही एक पॉलिमॉर्फिक वर्ग (उदाहरण के लिए vtable) के लिए कीमत का भुगतान करते हैं।

43

सी ++ 11 में आप उपयोग कर सकते हैं:

class MyClass 
{ 
    // create a virtual, default destructor 
    virtual ~MyClass() = default; 
}; 
+0

यह '' icpc'' के साथ संकलित है, लेकिन 'g ++ - 4.6.3'' नहीं है, और संदेश' 'त्रुटि देता है: ~ virtual MyClass :: ~ MyClass() घोषित वर्चुअल को क्लास बॉडी 'में डिफॉल्ट नहीं किया जा सकता है। बहुत स्पष्ट दिखता है कि वे नहीं चाहते हैं कि आप ऐसा करें; क्या 'g ++' 'का एक संस्करण है जिसके साथ यह काम करता है? – user14717

+1

@ निकटॉम्पसन, मैंने इसे जीसीसी 4.8.1 और 4.9.0 सफलतापूर्वक उपयोग किया है। ऐसा लगता है कि यह 4.6 में समर्थित है] (https://gcc.gnu.org/gcc-4.6/cxx0x_status.html)। क्या आप '-std = C++ 0x' के साथ संकलित कर रहे हैं? –

+0

मैं था; यकीन नहीं है कि वहां क्या हो रहा था। – user14717

2

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

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