2013-02-06 29 views
5

का उपयोग करते समय अजीब डबल विनाशक कॉल अंत में मैंने बहुत अजीब बग को ट्रैक किया, जो डबल कॉलिंग विनाशक के कारण होता है।share_ptr

#include <iostream> 
#include <memory> 
#include <set> 

class cEventSystem { 
    public: 
     cEventSystem() { 
      std::cout << "constructor: " << this << std::endl; 
     } 
     ~cEventSystem() { 
      std::cout << "destructor: " << this << std::endl; 
     } 
}; 

class cSubscriber { 
    public: 
     cSubscriber(cEventSystem& eventSystem) : eventSystem(eventSystem) {} 
     virtual ~cSubscriber() {} 
     virtual void onEvent() = 0; 
    protected: 
     cEventSystem& eventSystem; 
}; 

class cTileBrowser: public cSubscriber { 
    public: 
     cTileBrowser(cEventSystem eventSystem) : cSubscriber(eventSystem) {} 
     void onEvent() {} 
}; 

class cGui: public cSubscriber { 
    public: 
     cGui(cEventSystem& eventSystem) : cSubscriber(eventSystem) { 
      tileBrowser = std::make_shared<cTileBrowser>(eventSystem); 
     } 
     void onEvent() {} 
     std::shared_ptr<cTileBrowser> tileBrowser; 
}; 

int main() { 
    cEventSystem eventSystem; 
    cGui gui(eventSystem); 
} 

उत्पादन होता है:: यहाँ कम से कम कोड है कि बग को पुनरुत्पादित करता है

constructor: 0x7fffffffe67f 
destructor: 0x7fffffffe2df 
destructor: 0x7fffffffe67f 

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

डीबगिंग से पता चलता है कि यह make_shared है जो विनाशक कॉल का कारण बनता है।

क्या अवांछित विनाशक कॉल का कारण बनता है और मैं इससे कैसे छुटकारा पा सकता हूं? मैं सी ++ 11 ध्वज के साथ जी ++ 4.7 का उपयोग करता हूं।

समस्या यह है कि अवांछित नाशक कॉल आमतौर पर (90 बार का%) मेरा असली कोड जो segfaults का कारण बनता है में अपने घटना प्रणाली कंटेनरों को बिगाड़ देती है, लेकिन शायद ही कभी यह यह भ्रष्ट नहीं है और सब कुछ काम करता है।

उत्तर

11

CTileBrowser कन्स्ट्रक्टर मूल्य द्वारा अपना तर्क ले रहा है। आप उस कन्स्ट्रक्टर के लिए बनाई गई अस्थायी प्रतिलिपि के विनाश को देख रहे हैं। इसे संदर्भ पैरामीटर में बदलें और मुझे लगता है कि समस्या दूर हो जाएगी।

+0

आदमी, आप नायक हैं, यह अब मेरे असली कोड में काम करता है! लेकिन अस्थायी प्रति इतनी असुरक्षित क्यों है कि यह मेरे डेटा को स्मृति में दूषित कर सकती है? मैं लगभग हमेशा संदर्भ से गुजरता हूं (यह एक गलती थी), लेकिन यह मेरे लिए कम से कम अजीब लगता है। – user1873947

+2

@ user1873947, चूंकि कॉपी कन्स्ट्रक्टर संकलक उत्पन्न होता है, यह शायद गलत चीज कर रहा है। यदि यह उदाहरण के लिए पॉइंटर की एक प्रति बनाता है और विनाशक इसे हटा देता है, तो आपको मूल ऑब्जेक्ट में एक खतरनाक पॉइंटर के साथ छोड़ दिया जाता है। –

+0

@ मार्क रान्ससम यह है। मेरे असली कोड में मेरे पास पॉइंटर्स का एक सेट है। – user1873947