2011-07-20 18 views
7

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

मेरी परियोजना में एक डीएलएल (जो इसके नाम से निर्दिष्ट है) एक नया ग्रैबर ऑब्जेक्ट देता है। मेरी कोड के पिछले संस्करण में, DLL इस तरह एक समारोह का निर्यात:

extern "C" 
__declspec(dllexport) Grabber* CreateGrabber(string settings) 
{ 
    return new SomeSpecificGrabber(settings); 
} 

EXE में मैं एक नया धरनेवाला वस्तु बनाने के लिए इस तरह एक स्थिर समारोह का प्रयोग किया:

static Grabber* createGrabberObject(const std::string& grabberType, const std::string& grabberSettings) 
{ 
    FARPROC hProc = 0; 

    // load dll with the name of grabberType 
    HMODULE hDLL = LoadLibrary(grabberType.c_str()); 

    // get address for CreateGrabber function 
    hProc = GetProcAddress(hDLL, "CreateGrabber"); 

    // instantiate a function pointer of our type and typecast the address 
    // of the CreateGrabber function to this type 
    CreateGrabberFunctionType CreateGrabberFunction = (CreateGrabberFunctionType)hProc; 

    // call CreateGrabber in DLL to get a Grabber object 
    return CreateGrabberFunction(grabberSettings); 
} 

EXE में वह पंजे वस्तु के जीवनकाल एक स्मार्ट सूचक द्वारा किया जाता है:

shared_ptr<Grabber> myGrabberObj = shared_ptr<Grabber>(createGrabberObject("SomeGrabber.DLL", "Settings")); 

यह सब जब तक मैं EXE और /MDd सेटिंग (वीसी ++ 2010) के साथ DLL संकलित ठीक काम किया, whi सी का मतलब है कि ईईई और डीएलएल ने एक ही ढेर का इस्तेमाल किया था।

अब मैं /MTd सेटिंग के साथ अपना समाधान संकलित करना चाहता हूं। इसके साथ मुझे डीएलएल में पारित सेटिंग्स स्ट्रिंग ऑब्जेक्ट के लिए _CrtIsValidHeapPointer प्रकार का रनटाइम assert मिला। यह समझ में आता है क्योंकि डीएलएल एक स्ट्रिंग ऑब्जेक्ट को हटाने की कोशिश करता है जो EXE में बनाया गया था। और वे अब एक ही ढेर का उपयोग नहीं करते हैं।

मैं निर्यात DLL समारोह एक छोटा सा (string की const char* बजाय) बदल कर इस समस्या को हल मिल गया:

extern "C" 
__declspec(dllexport) Grabber* CreateGrabber(const char* settings) 
{ 
    return new SomeSpecificGrabber(settings); 
} 

और createGrabberObject में मैं DLL कार्य करने के लिए grabberSettings.c_str() बजाय grabberSettings गुजरती हैं।

अब सब कुछ ठीक काम करता है। लेकिन अब मेरा पहला प्रश्न आता है: हटाए जाने पर मुझे _CrtIsValidHeapPointer दावा क्यों नहीं मिलता है? ऑब्जेक्ट डीएलएल के भीतर से बनाया गया था लेकिन EXE (स्मार्ट पॉइंटर द्वारा) से हटा दिया गया है। मेरे ऊपर उपरोक्त स्ट्रिंग ऑब्जेक्ट के समान समस्या क्यों नहीं है?

मुझे लगता है कि एक साफ समाधान हो सकता है कि DLL भी इस तरह एक समारोह का निर्यात करता है:

static void deleteGrabberObject(const std::string& grabberType, Grabber* grabber) 
{ 
    FARPROC hProc = 0; 

    // load dll with the name of grabberType 
    HMODULE hDLL = LoadLibrary(grabberType.c_str()); 

    // get address for DeleteGrabber function 
    hProc = GetProcAddress(hDLL, "DeleteGrabber"); 

    // instantiate a function pointer of our type and typecast the address 
    // of the DeleteGrabber function to this type 
    DeleteGrabberFunctionType DeleteGrabberFunction = (DeleteGrabberFunctionType)hProc; 

    // call DeleteGrabber in DLL 
    DeleteGrabberFunction(grabber); 
} 
:

extern "C" 
__declspec(dllexport) void DeleteGrabber(Grabber* grabber) 
{ 
    delete grabber; 
} 

तो मैं भी मेरी EXE जो एक DLL में DeleteGrabber कॉल में एक स्थिर समारोह के लिए होता है

यह स्थिर समारोह फिर स्वचालित रूप से स्मार्ट सूचक द्वारा कहा जा सकता है:

shared_ptr<Grabber> myGrabberObj = shared_ptr<Grabber>(createGrabberObject("SomeGrabber.DLL", "Settings"), 
boost::bind(deleteGrabberObject, "SomeGrabber.DLL", _1)); 

यह भी काम करता है। लेकिन यहां मेरा दूसरा प्रश्न आता है: स्थिर कार्य createGrabberObject और deleteGrabberObject दोनों डीएलएल लोड करते हैं। क्या इसका मतलब यह है कि दो अलग-अलग ढेर बनाए जाते हैं क्योंकि डीएलएल के दो उदाहरण लोड होते हैं (फिर यह समाधान मेरी समस्या को हल नहीं करेगा)? या ये दो स्थिर कार्य एक ही ढेर का उपयोग करते हैं?

मुझे आशा है कि कोई यह बता सकता है कि यहां क्या हो रहा है ...

उत्तर

5

डीएलएल संदर्भित किया गया है, दो बार लोड नहीं किया गया है, और जब आप लोड लाइब्रेरी का उपयोग करते हैं तो यह केवल वही लोड हो जाता है और वे एक ही ढेर का उपयोग करेंगे। स्थैतिक कार्य इस समस्या का सामान्य समाधान है।

+0

धन्यवाद! यह वास्तव में तेज़ था! –

3

अपने दूसरे प्रश्न के लिए, सिर्फ इसलिए कि आप दो बार डीएलएल लोड करते हैं इसका मतलब यह नहीं है कि दो उदाहरण हैं। ओएस केवल एक बार लोड करने के लिए पर्याप्त स्मार्ट है।

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

+0

त्वरित प्रतिक्रिया के लिए धन्यवाद! असल में साझा सूचक स्कोप से बाहर हो जाता है (डीएलएल में '~ कुछ स्पेसिफिकग्रेबर 'में ब्रेकपॉइंट मारा जाता है)। तो ऐसा लगता है कि वीसी रनटाइम बस इसका पता नहीं लगा। –

3

ठीक है, ऐसा इसलिए है क्योंकि (आपके मामले में), दो ढेर काम कर रहे हैं। डीएलएल में एक और ढेर-मैनेजर है, और EXE अलग है।

  • डीबग/रिलीज विरोधाभास
  • VC-क्रम का इस्तेमाल किया (एक, VC8 है एक उदाहरण के लिए VC9 है): इसका कारण यह है की हो सकता है। ऊपर भी मिश्रित!
  • डीएलएल/EXE (/MT[d] ध्वज, स्थिर-lib आदि के रूप में जोड़ने) बनाने के लिए उपयोग किए जाने वाले विभिन्न मॉडल)।
  • आपने deletenew के विरुद्ध दिखाया है जो मान्य है। लेकिन यह भी मामला हो सकता है जहां new वास्तव में malloc/HeapAlloc है।

संक्षेप में, स्मृति एक्स ढेर-प्रबंधक द्वारा आवंटित वाई ढेर-प्रबंधक द्वारा पाया नहीं किया जाएगा, और इसलिए दावा!

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