2010-07-20 10 views
5

मेरी राय में, निम्नलिखित कोड (कुछ सी ++ प्रश्न से) को यूबी का नेतृत्व करना चाहिए, लेकिन ऐसा लगता है कि ऐसा नहीं है। यहाँ कोड है:क्या स्पष्ट रूप से विनाशकारी परिणाम को अपरिभाषित व्यवहार में बुला रहा है?

#include <iostream> 
using namespace std; 
class some{ public: ~some() { cout<<"some's destructor"<<endl; } }; 
int main() { some s; s.~some(); } 

और जवाब है:

some's destructor 
some's destructor 

मैं प्रपत्र सीखा C++ फैक लाइट है कि हम स्पष्ट रूप से नाशक नहीं बुलाना चाहिए। मुझे लगता है कि स्पष्ट रूप से विनाशक को बुलाए जाने के बाद, वस्तु को हटा दिया जाना चाहिए। कार्यक्रम समाप्त होने पर स्वचालित रूप से विनाशक को फिर से कॉल करता है, यह यूबी होना चाहिए। हालांकि, मैंने इसे g ++ पर आज़माया, और उपर्युक्त उत्तर के समान परिणाम प्राप्त किया।

क्या ऐसा इसलिए है क्योंकि कक्षा बहुत सरल है (कोई नया/शामिल नहीं है)? या यह इस मामले में यूबी नहीं है?

+10

* अपरिभाषित व्यवहार * का पूरा बिंदु यह है कि यह ** अनिर्धारित ** है। तथ्य यह है कि यह "काम करता है" अनंत संभावनाओं में से एक है। – ereOn

+0

यह विनाशक हानि प्रभाव के लिए बहुत आसान है। मेरा मानना ​​है कि विनाशक को बुलाकर एक विशेष मामला नहीं है, बल्कि कक्षा की विधि को बुला रहा है। इसे हटाए जाने से पहले सही कहने का विशेष मामला है (हटाएं या दायरे से बाहर निकलने से)। –

+0

@ereOn: धन्यवाद। मैं समझता हूं कि जी ++ में यह "काम करता है" इसका मतलब यह नहीं है कि यह "अपरिभाषित" नहीं है। हालांकि, ऑनलाइन उत्तर (जो सही नहीं हो सकता है) यूबी नहीं है, इसलिए मैं उलझन में हूं। – EXP0

उत्तर

15

व्यवहार अपरिभाषित है क्योंकि नाशक एक ही वस्तु के लिए दो बार शुरू हो जाती है:

  • एक बार जब आप इसे आह्वान स्पष्ट
  • एक बार जब गुंजाइश समाप्त हो जाती है और स्वत: चर
नष्ट हो जाता है

किसी ऑब्जेक्ट पर विनाशक को आमंत्रित करना जिसका जीवनकाल समाप्त हो गया है, प्रति सी ++ 03 §12.4/6:

व्यवहार करता है, तो नाशक एक वस्तु जिसका जीवन समाप्त हो गया है शुरू होता है अपरिभाषित है

वस्तु का जीवनकाल समाप्त होता है जब इसके नाशक प्रति §3.8/1 कहा जाता है:

एक वस्तु का जीवन प्रकार के T समाप्त होता है जब:

- अगर T एक गैर तुच्छ नाशक (12.4) के साथ एक वर्ग प्रकार है, नाशक कॉल शुरू होता है, या

- ऑब्जेक्ट पर कब्जा कर लिया गया भंडारण पुन: उपयोग या जारी किया जाता है।

नोट मतलब है कि यह अगर अपनी कक्षा एक छोटी सी नाशक है, व्यवहार अच्छी तरह से परिभाषित है, क्योंकि इस तरह के एक प्रकार का ऑब्जेक्ट के जीवनकाल तक इसके भंडारण जारी की है अंत नहीं है, जो स्वत: चर के लिए नहीं होता है समारोह के अंत तक। बेशक, मुझे नहीं पता कि अगर आप तुच्छ हैं तो आप विनाशकारी को स्पष्ट रूप से क्यों बुलाएंगे।

एक छोटा विनाशक क्या है? §12.4/3 का कहना है:

एक नाशक तुच्छ है अगर यह एक परोक्ष-घोषित नाशक है और यदि:

- अपने वर्ग के प्रत्यक्ष आधार वर्ग के सभी तुच्छ विनाशकर्ता है और

- अपनी कक्षा के सभी गैर स्थैतिक डेटा सदस्यों के लिए जो वर्ग प्रकार (या सरणी) हैं, प्रत्येक वर्ग में एक छोटा विनाशक होता है।

दूसरों के रूप में उल्लेख किया है, अपरिभाषित व्यवहार में से एक संभव परिणाम सही ढंग से निरंतर चलाने के लिए प्रदर्शित होने के अपने कार्यक्रम है, एक और संभावित परिणाम आपका प्रोग्राम दुर्घटनाग्रस्त है। कुछ भी हो सकता है और कोई भी गारंटी नहीं है।

+0

धन्यवाद। मेरे पास मानक दस्तावेज नहीं है, और मुझे एहसास हुआ कि मुझे एक प्राप्त करने के लिए भुगतान करना होगा। क्या आप "गैर-तुच्छ विनाशक" की परिभाषा प्रदान करना चाहते हैं? सवाल में एक गैर-तुच्छ विनाशक है? धन्यवाद। – EXP0

+0

@ EXP0: मैंने आपके लिए एक छोटे से विनाशक की परिभाषा को जोड़ा। प्रश्न में विनाशकारी एक छोटा विनाशक नहीं है। –

+0

@JamesMcNellis, पैराग्राफ क्या कहता है वही नहीं है जैसा आप समझते हैं। पैराग्राफ कहता है कि किसी ऑब्जेक्ट के विनाशक को हटा दिया गया है, और सवाल यह है कि विनाशक को सामान्य विधि के रूप में * इसे नष्ट करने से पहले कॉल करने के लिए कहा जा रहा है। यह वही बात नहीं है। स्पष्ट रूप से विनाशक को बुलाकर वस्तु को हटा नहीं देता है। उदाहरण के लिए आपको 'डिलीट' ऑपरेटर को कॉल करने के लिए ऑब्जेक्ट को स्पष्ट रूप से हटाएं (और यह स्वचालित नहीं है) बीटीडब्लू, मैंने कभी विनाशक को बुलाए जाने की संभावना के बारे में कभी नहीं सुना है, क्योंकि इसे '~' ऑपरेटर के रूप में व्याख्या किया जाना चाहिए। –

1

यहां समस्या यह है कि हटाना/हटाना और विनाशक अलग और स्वतंत्र संरचनाएं हैं। नए/आवंटन और रचनाकारों की तरह। उपरोक्त में से केवल एक को दूसरे के बिना करना संभव है।

सामान्य स्थिति में इस परिदृश्य में उपयोगिता की कमी होती है और केवल आवंटित मूल्यों के साथ भ्रम पैदा होती है। मेरे सिर के ऊपर से मैं एक अच्छा परिदृश्य नहीं सोच सकता जहां आप ऐसा करना चाहते हैं (हालांकि मुझे यकीन है कि संभावित रूप से एक है)। हालांकि, प्रदूषित परिदृश्यों के बारे में सोचना संभव है जहां यह कानूनी होगा।

class StackPointer<T> { 
    T* m_pData; 
public: 
    StackPointer(T* pData) :m_pData(pData) {} 
    ~StackPointer() { 
    delete m_pData; 
    m_pData = NULL; 
    } 
    StackPointer& operator=(T* pOther) { 
    this->~StackPointer(); 
    m_pData = pOther; 
    return this; 
    } 
}; 

नोट: कृपया कभी एक वर्ग इस तरह से कोड नहीं है। इसके बजाय एक स्पष्ट रिलीज विधि है।

+1

'std :: vector' (दूसरों के बीच) के लिए कोड अच्छा दिखाएगा स्पष्ट dtor आमंत्रण के लिए उपयोग करें। –

+0

@ जेरी, बहुत सच है लेकिन ढेर मूल्यों के लिए नहीं है जो * लगता है * ओपी के प्रश्न का केंद्र होना प्रतीत होता है। – JaredPar

+0

हां, उस प्रतिबंध के साथ यह एक उचित परिदृश्य के साथ आने के लिए एक * बहुत * कठिन है। –

1

यह संभवतः ठीक काम करता है क्योंकि विनाशक किसी वर्ग सदस्य चर का संदर्भ नहीं देता है। यदि आपने विनाशक के भीतर delete एक चर का प्रयास करने की कोशिश की है तो आप शायद दूसरी बार स्वचालित रूप से कॉल होने पर परेशानी में भाग लेंगे।

फिर फिर, अपरिभाषित व्यवहार के साथ, कौन जानता है? :)

6

यह अनिर्धारित व्यवहार है - लेकिन किसी भी यूबी के साथ, एक संभावना यह है कि कम से कम काम की कुछ परिभाषा के लिए यह (अधिक या कम) काम करने लगता है।

अनिवार्य रूप से केवल एक समय जब आप को विनाशक का आह्वान करने की आवश्यकता होती है (या चाहते हैं) प्लेसमेंट के साथ संयोजन के रूप में है (यानी, आप किसी निर्दिष्ट स्थान पर ऑब्जेक्ट बनाने के लिए नया प्लेसमेंट का उपयोग करते हैं, और उस ऑब्जेक्ट को नष्ट करने के लिए एक स्पष्ट डॉटोर आमंत्रण)।

+0

-1 लेकिन यह अपरिभाषित नहीं है। भाषा इस तरह से स्पष्ट कॉल की अनुमति देती है क्योंकि इसका उपयोग किया जा सकता है और उपयोगी हो सकता है। – Elemental

+3

@Elemental: एक स्पष्ट डॉटोर आमंत्रण स्वयं में यूबी नहीं है - लेकिन एक ही ऑब्जेक्ट को दो बार निश्चित रूप से नष्ट करना ** ** ** यूबी है। वास्तव में, यह मानक (§12.4/14) में दिया गया एक उदाहरण है: "एक वस्तु के लिए विनाशक को बुलाया जाने के बाद, ऑब्जेक्ट अब मौजूद नहीं है; यदि व्यवहार किसी ऑब्जेक्ट के लिए विनाशक को बुलाया जाता है तो व्यवहार अनिश्चित होता है जिसका जीवनकाल समाप्त हो गया है (3.8)। [उदाहरण: यदि किसी स्वचालित ऑब्जेक्ट के लिए विनाशक को स्पष्ट रूप से बुलाया जाता है, और ब्लॉक को बाद में इस तरह से छोड़ा जाता है जो सामान्य रूप से वस्तु के निहित विनाश का आह्वान करता है, तो व्यवहार अपरिभाषित होता है।] " –

0

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

वैसे भी आपको नियुक्ति-नए के साथ बनाई गई वस्तुओं को छोड़कर, किसी ऑब्जेक्ट के विनाशक को मैन्युअल रूप से कॉल नहीं करना चाहिए।

3

http://www.devx.com/tips/Tip/12684

अपरिभाषित व्यवहार से पता चलता है कि एक कार्यान्वयन अप्रत्याशित व्यवहार कर सकता है जब एक प्रोग्राम एक निश्चित राज्य है, जो लगभग बिना किसी अपवाद के एक बग का एक परिणाम है तक पहुँचता है। अपरिभाषित व्यवहार को रन टाइम क्रैश, अस्थिर और अविश्वसनीय प्रोग्राम स्थिति के रूप में प्रकट किया जा सकता है, या - दुर्लभ मामलों में - यह अनजान भी अनदेखा कर सकता है।

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

0

मेरा मानना ​​है कि यदि आप चाहते हैं कि आपका कोड ठीक है तो आपको बस प्लेसमेंट को कॉल करने और इसे बाहर निकलने से पहले इसे भरने की आवश्यकता है। विनाशक को फोन मुद्दा नहीं है, जब आप गुंजाइश छोड़ते हैं तो विनाशक को यह दूसरा कॉल है।

0

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

0

यह अपरिभाषित व्यवहार है। अपरिभाषित व्यवहार डबल विनाशक कॉल है, न कि विनाशक कॉल के साथ। आप के लिए अपने उदाहरण में बदलाव हैं:

#include <iostream> 
using namespace std; 
class some{ public: ~some() { [INSERT ANY CODE HERE] } }; 
int main() { some s; s.~some(); } 

जहां [किसी भी कोड दर्ज करें] किसी भी मनमाने ढंग से कोड के साथ बदला जा सकता है। परिणामों के अप्रत्याशित साइड इफेक्ट्स हैं, यही कारण है कि इसे अपरिभाषित माना जाता है।

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