2012-10-05 13 views
6

मैं एक नाशक के साथ एक समस्या हो रहा है एक सबरूटीन भले ही यह सबरूटीन के दायरे से बाहर परिभाषित किया जाना चाहिए के अंत में एक वर्ग के लिए बुलाया जा रहा है।सी ++: नाशक से पहले यह क्षेत्र से बाहर जाना चाहिए बुलाया जा रहा है?

#include <iostream> 
using namespace std; 

class Foo { 
private: 

    double *array; 

public: 

Foo(int N) { 
    array = new double[N]; 
    for (int i=0; i<N; i++) { 
     array[i]=0; 
    } 
} 

~Foo() { 
    delete[] array; 
} 
}; 

void subroutine(Foo x) { 
    cout << "Hello!" << endl; 
} 

int main() { 
    Foo bar(10); 
    subroutine(bar); 
    subroutine(bar); 
} 

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

यहाँ कि मेरी समस्या को प्रदर्शित करता है कोड मैं सबसे छोटी टुकड़ा है मुख्य कार्य? इसका मतलब यह है कि जब मैं दूसरा सबराउटिन कहता हूं तो विनाशक को फिर से बुलाया जाता है और मुझे स्मृति रिसाव मिलती है।

मैं पाया है मैं सबरूटीन में संदर्भ द्वारा फोन करके इसे ठीक कर सकते हैं, लेकिन मैं इसे ठीक से बहुत संतुष्ट के बाद मुझे समझ में क्यों यह पहली जगह में काम नहीं किया न नहीं कर रहा हूँ। क्या कोई इस पर मेरे लिए कुछ प्रकाश डाल सकता है?

धन्यवाद।

+2

अपने विनाशक को देखते हुए, आपको 'Foo' की प्रतिलिपि बनाने और प्रतिलिपि असाइनमेंट ऑपरेटर को परिभाषित करने या हटाने की आवश्यकता है। "तीन के नियम" के लिए खोजें। –

+5

"विनाशक को कक्षा के लिए बुलाया जा रहा है" - आप पाएंगे कि, समय के साथ, चीजें अधिक स्पष्ट होती हैं यदि आप लगातार ** कक्षा ** और ** ऑब्जेक्ट ** के बीच अंतर करते हैं। विधियों को ** वस्तुओं पर नहीं कहा जाता है ** कक्षाओं पर नहीं। –

उत्तर

21

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

void subroutine(Foo x) { 
    // x is a new Foo here. It will get destroyed on exiting scope, 
    // resulting in a destructor call 
} 

आपका मुख्य समस्या यह है कि यहाँ आप एक प्रति निर्माता लागू नहीं किया है, तो गतिशील रूप से आवंटित सरणी कॉपी नहीं है (केवल सूचक है कि यह है की ओर इशारा करता है)। इसलिए, जब आप Foo वस्तुओं कॉपी, आप प्रत्येक प्रतिलिपि एक ही सरणी की चर्चा करते हुए की है। और प्रत्येक प्रति इसे नष्ट करने की कोशिश करेगी।

आपको rule of three का पालन करना चाहिए और एक असाइनमेंट ऑपरेटर और एक कॉपी कन्स्ट्रक्टर लागू करना है जो सरणी की "गहरी प्रति" बनाता है, जैसे प्रत्येक Foo ऑब्जेक्ट का अपना सरणी है।

+0

आह त्वरित उत्तर के लिए धन्यवाद! हां मैंने देखा था कि संदर्भ द्वारा कॉलिंग ने इसे ठीक किया लेकिन मुझे नहीं पता था कि स्पष्टीकरण के लिए धन्यवाद क्यों! – Plog

+1

@ user1722882: वास्तव में, आप 'std :: vector' का उपयोग करके बेहतर हो जाएंगे और अपने विनाशक को पूरी तरह से हटा दें। मानक पुस्तकालय कंटेनरों को पुन: कार्यान्वित करना इसके खेल के लिए अच्छा हो सकता है, लेकिन जब यह व्यायाम/नौकरी का प्राथमिक उद्देश्य नहीं है ... यह सिर्फ आपकी उत्पादकता को मार रहा है। C12+ 11 के साथ –

1
आपको हो रही समस्या

है कि आप मूल्य के आधार पर आपके वस्तु गुजर रहे हैं:

void subroutine(Foo x) { 

यह एक अस्थायी वस्तु बनाने और प्रतिलिपि निर्माता/हर बार जब आप इसे कहते आपके वस्तु का नाशक लागू कर रहा है।

3

जब आप void subroutine(Foo x) { पर कॉल करते हैं तो आपकी ऑब्जेक्ट bar कॉपी की जाती है (इस प्रकार कार्यकर्ता को फ़ंक्शन समाप्त होने के बाद बुलाया जाता है)।

उपयोग करने का प्रयास करें: void subroutine(Foo &x) {, यह ठीक काम करना चाहिए।

6

आप मान द्वारा बार गुजर रहे हैं तो एक प्रति बनाया जा रहा है सबरूटीन के लिए। बनाने से बचने के लिए एक प्रति संदर्भ द्वारा इसे पारित:

void subroutine(Foo& x) 
{ 
    cout << "Hello!" << endl; 
} 

आप प्रतिलिपि निर्माता की घोषणा के द्वारा अपने वर्ग के आकस्मिक प्रतियां रोकने के लिए और कॉपी इस तरह असाइनमेंट ऑपरेटर निजी कर सकते हैं:

class Foo { 
private: 

    double *array; 

    Foo(const Foo&); 
    Foo& operator=(const foo&); 

public: 
    ... 
}; 

तो फिर तुम एक संकलन मिल इसके बजाय त्रुटि। क्या तुम सच में अपने वर्ग की एक प्रतिलिपि बनाने के लिए सक्षम होने की जरूरत है, तो आप वास्तव में इन कार्यों को लागू करने के लिए एक "गहरी प्रतिलिपि" प्रदर्शन करने के लिए (या बेहतर अभी तक std::vector<float> का उपयोग करें और है कि सुरक्षित नकल सहित आप के लिए स्मृति का प्रबंधन करते हैं) की आवश्यकता होगी।

+0

इसके बजाय उन्हें 'हटाए गए' के ​​रूप में घोषित करना बेहतर है –

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