2016-04-28 3 views
5

आप एक नाशक के बिना एक वर्ग है, तो:मानक मुझे विनाशकों के बिना वर्ग आवंटित करने के लिए क्यों मुक्त करता है?

struct A { 
    ~A() = delete; 
}; 

मानक नहीं करता है मुझे "स्थानीय रूप से" उस वर्ग का एक उदाहरण का आवंटन:

int main() 
{ 
    A a; //error 
} 

लेकिन ऐसा लगता है जैसे कि यह करता है, तो ठीक है मैं आवंटन पर मुफ्त की दुकान है कि:

int main() 
{ 
    a *p = new A(); 
} 

जब तक मैं न फोन है कि सूचक पर हटाएँ:

+०१२३५१६४१०
int main() 
{ 
    a *p = new A(); 
    delete p; //error 
} 

तो मेरा सवाल यह है कि मानक मुझे बिना किसी विनाशक के कक्षा क्यों दे सकता है अगर मैं इसे फ्री-स्टोर पर आवंटित करता हूं? मुझे लगता है कि इसके लिए कुछ उपयोग के मामले हैं? लेकिन वास्तव में क्या?

+14

सी ++ में आप कई चीजें कर सकते हैं, जो आपको नहीं करना चाहिए। यह उनमें से एक होगा। –

+0

अब मैं इस बारे में उत्सुक हूं ... – callyalater

+4

ऐसा नहीं है कि मानक निर्धारित करता है कि स्मृति लीक वर्जित हैं। शायद एक और दिलचस्प सवाल होगा: मानक विनाशकों को हटाने की अनुमति क्यों देता है? – jamesdlin

उत्तर

7

तो मेरे सवाल है, क्यों मानक मुझे एक डालते हैं करता है यदि मैं इसे फ्री-स्टोर पर आवंटित करता हूं तो विनाशक के बिना कक्षा?

क्योंकि वह नहीं कैसे मानक सुविधाओं काम है।

= delete वाक्य रचना के बारे में आप कई समस्याओं का हल करने के लिए आविष्कार किया गया था बात कर रहे हैं। उनमें से एक बहुत विशिष्ट था: ऐसे प्रकार बनाना जो केवल-केवल या स्थिर थे, जिसके लिए संकलक issue a compile-time error होगा यदि आपने प्रतिलिपि (या चाल) कन्स्ट्रक्टर/असाइनमेंट ऑपरेटर को कॉल करने का प्रयास किया था।

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

और एक वर्ग के नाशक के रूप में "किसी भी समारोह" में उत्तीर्ण।

सुविधा के लिए डिज़ाइन किया गया आशय प्रकार जो गैर destructible होगा बनाने के लिए नहीं था। यह किसी भी समारोह पर =delete की अनुमति देने का एक विस्तार है। यह डिजाइन या इरादा नहीं है; यह बस है।

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

5
इस के साथ

:

A a; 

आप गुंजाइश बाहर निकलने पर नाशक कॉल करेंगे (और आप नाशक, इसलिए त्रुटि नष्ट कर दिया है)। इस के साथ:

A *a = new A(); 

आप बस नाशक फोन नहीं है (क्योंकि आप delete का उपयोग कभी नहीं)। कार्यक्रमों को पूरा होने पर स्मृति साफ हो जाती है, लेकिन आप अनिवार्य रूप से स्मृति रिसाव की गारंटी दे रहे हैं।

इस व्यवहार को अस्वीकार करने के लिए c++ का कोई कारण नहीं है क्योंकि यह एक कंपाइलर में प्रोग्राम के लिए एक बहुत ही विशिष्ट मामला बन जाएगा। उदाहरण के लिए, c++ इस नामंज़ूर नहीं करता है:

int *p; *p = 5; 

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

कोई कारण नहीं है कि आपको अपने विनाशक को हटाना चाहिए क्योंकि यह एक उपयोगी व्यवहार नहीं है।

+0

क्या आपका मतलब यह है कि यह भाषा नियमों के एक सेट का सिर्फ एक प्यारा साइड इफेक्ट है जो अन्य उपयोगी सामानों की अनुमति देता है, और हमारी भाषा डिजाइनर कुछ व्यापार-बंदों पर विचार करने के बाद इसे बंद नहीं करने का फैसला करते हैं? –

+0

@NickyC या तो यह बंद करने के लायक नहीं था क्योंकि यह कंपाइलर्स लिखने वाले लोगों के लिए अनावश्यक जटिलता को जोड़ देगा, जब उनके सही दिमाग में कोई भी उद्देश्य पर उनके कोड में नहीं लिखता है। –

+0

यह वास्तव में प्रश्न का उत्तर देता है। मैं इसके पीछे तर्क समझता हूं। लेकिन फिर एक और सवाल यह है कि फ्री-स्टोर आवंटन को मजबूर क्यों करें? – Mac

1

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

मानक का तात्पर्य है कि गतिशील भंडारण अवधि के साथ एक निर्मित वस्तु विनाशक आमंत्रण के लिए योग्य नहीं है।

12,4 Destructors [class.dtor]

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


हम धागे के बीच एक बुनियादी स्मृति उदाहरण साझा करने के माध्यम से इस के लाभ देख सकते हैं:

#include <thread> 
#include <iostream> 

//shared object 
struct A { 

    void say_hello(){ std::cout << ++value << '\n'; } 
    ~A() = delete; 
    int value; 
}; 

//two threads 
void creator(); 
void user(A* a); 

//the creator allocates memory, 
//gives it to another thread (via pointer), 
//and then ends gracefully. 
//It does not attempt to implicitly call the destructor. 
//Nor would we want it to for allocated memory we are sharing. 
void creator(){ 

    A* a = new A(); 
    a->value = 0; 
    std::thread t(user, a); 
    t.detach(); 
} 

//The user recieves a pointer to memory, 
//and is free to continue using it 
//despite the creator thread ending 
void user(A* a){ 
    while(1){ 
    a->say_hello(); 
    } 
} 

//main->creator->user 
int main(){ 
    std::thread t(creator); 
    while(1){} 
} 

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

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