2010-08-07 32 views
16

का उपयोग करते समय std :: स्ट्रिंग के साथ मेमोरी लीक मैं अपने वर्तमान प्रोजेक्ट में std::list<std::string> के साथ काम कर रहा हूं। लेकिन इसके साथ कहीं जुड़े एक स्मृति रिसाव है। इसलिए मैंने समस्याग्रस्त कोड को अलग से परीक्षण किया है:std :: string <std::string>

#include <iostream> 
#include <string> 
#include <list> 

class Line { 
public: 
    Line(); 
    ~Line(); 
    std::string* mString; 
}; 

Line::Line() { 
    mString = new std::string("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); 
} 

Line::~Line() { 
    //mString->clear(); // should not be neccessary 
    delete mString; 
} 

int main(int argc, char** argv) 
{ 
    // no memory leak 
    while (1==1) { 
     std::string *test = new std::string("XXXXXXXXXXXXXXXXXXXXXXXX"); 
     delete test; 
    } 

    // LEAK! 
    // This causes a memory overflow, because the string thats added 
    // to the list is not deleted when the list is deleted. 
    while (1==1) { 
     std::list<std::string> *sl = new std::list<std::string>; 
     std::string *s = new std::string("XXXXXXXXXXXXXXXXXXXXXXX"); 
     sl->push_back(*s); 
     //sl->pop_back(); //doesn't delete the string?- just the pointer 
     delete sl; 
    } 

    // LEAK! 
    // Here the string IS deleted, but the memory does still fill up 
    // but slower 
    while (1==1) { 
     std::list<Line> *sl = new std::list<Line>; 
     Line *s = new Line(); 
     sl->push_back(*s); 
     //sl->pop_back(); //does delete the Line-Element 
     sl->clear(); 
     delete sl; 
    } 
    return 0; 

    // this does not cause any noticable memory leak 
    while (1==1) { 
     std::list<int> *sl = new std::list<int>; 
     int i = 0xFFFF; 
     sl->push_back(i); 
     sl->clear(); 
     delete sl; 
    } 
    return 0; 

    // This does not cause any overflow or leak 
    while (1==1) { 
     int *i; 
     i= new int [9999]; 
     delete[] i; 
    } 

} 

मेरी स्ट्रिंग सूची मेमोरी रिसाव क्यों करती है? सूची को हटाना नहीं चाहिए क्योंकि प्रत्येक निहित स्ट्रिंग पर विनाशकों को बुलाया जाना चाहिए?

+338

'नया' का उपयोग करना बंद करें। मैं आपके द्वारा कहीं भी नए इस्तेमाल किए गए किसी भी कारण को नहीं देख सकता। आप सी ++ में मूल्य से वस्तुओं को बना सकते हैं और यह भाषा का उपयोग करने के लिए एक बड़ा लाभ है। आपको ढेर पर सबकुछ आवंटित करने की आवश्यकता नहीं है। जावा प्रोग्रामर की तरह सोचना बंद करो। – Omnifarious

उत्तर

26

पहले मामले में, list कक्षा को पता नहीं है कि आपने स्ट्रिंग को new के साथ आवंटित किया है, और इसे हटा नहीं सकता है। विशेष रूप से, सूची में केवल आपके द्वारा पारित स्ट्रिंग की एक प्रति होती है।

इसी तरह, दूसरे मामले में, आप लाइन ऑब्जेक्ट s को कभी भी मुक्त नहीं करते हैं, और इस प्रकार आप स्मृति को रिसाव करते हैं। आंतरिक स्ट्रिंग को हटाए जाने का कारण यह है कि आपने एक कॉपी कन्स्ट्रक्टर को सही तरीके से कार्यान्वित नहीं किया है। इस प्रकार, यदि आप Line ऑब्जेक्ट की एक प्रति बनाते हैं, तो वे दोनों एक ही स्ट्रिंग पॉइंटर का संदर्भ लेंगे, और यदि आप दोनों को हटाने का प्रयास करते हैं, तो आप परेशानी में हैं।

7

यहाँ अपने रिसाव है:

while (1==1) { 
    std::list<Line> *sl = new std::list<Line>; 
    Line *s = new Line(); 
    sl->push_back(*s); 
    //sl->pop_back(); //does delete the Line-Element 
    sl->clear(); 
    delete sl; 
} 

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

आप दुकान संकेत करने के लिए है हैं, तो boost::shared_ptr तरह कामयाब संकेत संग्रहीत करने पर विचार, या Boost pointer container library पर गौर।

दूसरे रूप में, आपको ढेर पर Line आवंटित करने की आवश्यकता नहीं है। बस के लिए इसे बदल:

sl->push_back(Line()); 

और, जैसा कि अन्य लोगों का उल्लेख किया, यकीन है कि Line के सूचक सदस्यों ठीक से कॉपी-निर्माता में कामयाब रहे हैं, कॉपी-काम, और नाशक।

2
std::list<Line> *sl = new std::list<Line>; 
    Line *s = new Line(); 
    sl->push_back(*s); 
    //sl->pop_back(); //does delete the Line-Element 
    sl->clear(); 
    delete sl; 

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

12

आपकी लाइन क्लास को कॉपी-सीटर और असाइनमेंट ऑपरेटर की आवश्यकता होती है जो स्ट्रिंग पॉइंटर से ठीक से निपटती है।

वैकल्पिक रूप से, केवल एक पॉइंटर के बजाय std::string सदस्य है और string कक्षा मेमोरी को संभालने दें (यही वह है)।

2

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


जहां तक ​​उदाहरण यहाँ थेरेस के बाद आप उन्हें प्रयोग कर रहे हैं, जब वे दायरे में प्रवेश करने और उन्हें निकालने, कुछ भी करने के लिए संकेत का उपयोग करने के लिए जब वे गुंजाइश छोड़ कोई कारण पता चलता है - बस पर सब कुछ बनाने इसके बजाय ढेर और संकलक स्कॉप्स से बाहर निकलने पर सब कुछ ठीक से निपटान करेंगे। उदाहरण के लिए।

while (1==1) { 
    std::list<std::string> sl; 
    std::string s = std::string("XXXXXXXXXXXXXXXXXXXXXXX"); 
    sl.push_back(s); 
} 

आप, सूचक व्यवहार की जरूरत है आप स्मार्ट संकेत पर एक नज़र रखना चाहिए (वस्तुओं है कि बहुत सी बातें से भी संबद्ध हैं आदि आदि नकल करने से बचने के लिए) इन के रूप में कई को हटा देगा करते हैं नुकसान के कारण वे स्वचालित रूप से आवश्यक संदर्भ गणना और अर्थशास्त्र को संभाल सकते हैं। (विशेष रूप से take a look at the boost smart pointers)

स्मार्ट सूचक आप विशिष्ट की जरूरत है और स्वामित्व अर्थ का प्रतिनिधित्व करने के आधार पर उपयोग कर सकते हैं के कई प्रकार के होते हैं।

std :: auto_ptr का सख्त स्वामित्व है - यदि सूचक "मूल" कॉपी किया गया है तो मूल को हटा दिया गया है और स्वामित्व स्थानांतरित हो गया है - ऑब्जेक्ट में केवल एक वैध auto_ptr है। जब भी स्वामित्व वाला स्मार्ट पॉइंटर गुंजाइश से बाहर हो जाता है तब ऑब्जेक्ट को हटा दिया जाता है। जब मुक्त करने के लिए वस्तु की ओर इशारा किया जा रहा है

थेरेस भी साझा संकेत और कमजोर संकेत दिए गए संदर्भ गिनती का उपयोग कर पता करने के लिए बढ़ावा देने के। साझा पॉइंटर्स के साथ सूचक की प्रत्येक प्रति एक संदर्भ गणना बढ़ जाती है, और जब भी सभी साझा पॉइंटर्स दायरे से बाहर जाते हैं तो ऑब्जेक्ट को हटा दिया जाता है। एक कमजोर पॉइंटर एक साझा पॉइंटर द्वारा प्रबंधित ऑब्जेक्ट को इंगित करता है लेकिन संदर्भ गणना में वृद्धि नहीं करता है, अगर सभी अभिभावक साझा पॉइंटर्स को कमजोर करने का प्रयास हटा दिया जाता है तो कमजोर सूचक आसानी से पकड़ने योग्य अपवाद फेंक देगा।

जाहिर है एक बहुत स्मार्ट संकेत की श्रृंखला के लिए और अधिक theres, लेकिन मैं अत्यधिक एक समाधान के रूप में उन्हें पर एक नज़र लेने के लिए अपनी स्मृति के प्रबंधन के साथ मदद करने के लिए सुझाव देते हैं।

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