2012-03-23 7 views
7

मैं सोच रहा था कि विंडोज हैंडल के साथ unique_ptr<T> का उपयोग करने का कोई तरीका है या नहीं?विंडोज हैंडल के साथ सी ++ मानक स्मार्ट पॉइंटर्स का उपयोग कैसे करें?

मैं std::default_delete को विशिष्ट handle_trats के साथ प्रतिस्थापित करने के बारे में सोच रहा था जो CloseHandle पर कॉल करता है। समस्या यह है कि HANDLE को void*unique_ptr<void> के रूप में परिभाषित किया गया है sizeof(void) के रूप में संकलित नहीं किया जाएगा।

  1. संभालती के लिए एक आवरण वर्ग बना सकते हैं और इस तरह से इसका इस्तेमाल करते हैं: unique_ptr<new CHandle(h)>

    अब तक मैं केवल दो संभावनाएं देखते हैं। यह बहुत अधिक unique_ptr<T> स्वयं बेकार बनाता है।

  2. HANDLE विशिष्ट स्मार्ट पॉइंटर क्लास का उपयोग करें जो unique_ptr<T> जैसा दिखता है।

आपको क्या लगता है बेहतर विकल्प है? आप क्या सुझाव देंगे?

प्रश्न COM IUnknown पॉइंटर्स के लिए बढ़ाया जा सकता है - CComPtr किसी भी मानक स्मार्ट पॉइंटर्स द्वारा प्रतिस्थापित किया जा सकता है?

उत्तर

7

सवाल कॉम के लिए बढ़ाया जा सकता है (unique_ptr भी एक निर्माता है कि एक हटाएँ वर्ग प्राप्त करता है) अज्ञात पॉइंटर्स - क्या CComPtr किसी भी मानक स्मार्ट पॉइंटर्स द्वारा प्रतिस्थापित किया जा सकता है?

हां। आप std::default_deleter विशेषज्ञ नहीं हैं, आप बस डिलीटर प्रकार को प्रतिस्थापित करते हैं।

struct COMDeleter { 
    template<typename T> void operator()(T* ptr) { 
     ptr->Release(); 
    } 
}; 
unique_ptr<IUnknown, COMDeleter> ptr; // Works fine 

इसी सिद्धांत shared_ptr और वास्तव में करने के लिए लागू होता है, HANDLE करने के लिए।

6

एक विशिष्ट स्मार्ट पॉइंटर क्लास बनाएं, इसमें अधिक समय नहीं लगेगा। लाइब्रेरी कक्षाओं का दुरुपयोग मत करो। संभालना संवेदना एक सी ++ सूचक से काफी अलग है; एक बात के लिए, एक हैंडल को संदर्भित करने का कोई मतलब नहीं है।

कस्टम स्मार्ट हैंडल क्लास का उपयोग करने का एक और कारण - NULL का हमेशा एक खाली संभाल नहीं होता है। कभी-कभी यह INVALID_HANDLE_VALUE है, जो समान नहीं है (वास्तव में -1)।

+1

मैंने अपने स्वयं के सेट हैंडल-विशिष्ट वर्गों को लिखा है, क्योंकि कुछ हैंडल को 'क्लोजहैंडल()' की आवश्यकता होती है जबकि अन्य को अलग-अलग एपीआई-विशिष्ट फ़ंक्शन की आवश्यकता होती है, कुछ हैंडल INVALID_HANDLE_VALUE पर सेट होते हैं जब असाइन नहीं किए जाते हैं और अन्य इसके बजाय न्यूल पर सेट होते हैं, आदि। मैंने काम के थोक के लिए आधार वर्गों का एक सेट लिखा, और फिर बंद करने और असाइनमेंट मुद्दों को संभालने के लिए कस्टम विशेषता कक्षाओं का उपयोग करें। लाइब्रेरी कक्षाओं को फिर से कार्यान्वित करने के लिए –

+0

-1 बुरी तरह से। वे स्पष्ट रूप से इस कार्यक्षमता के लिए डिज़ाइन किए गए हैं, यह दुरुपयोग नहीं है। आप व्यर्थ नई बग और कोड पेश करेंगे। पॉइंटर्स और हैंडल को पहचानने के लिए – Puppy

+0

+1 विभिन्न अर्थशास्त्र के साथ अलग-अलग चीजें हैं। एक स्मार्ट पॉइंटर प्रकार में शोहोर्न हैंडल्स आपको उन तरीकों का एक समूह देता है जो वास्तव में हैंडल के लिए समझ में नहीं आता है। –

0

आपको delete का उपयोग करके एक हैंडल को "बंद" करने के लिए CloseHandle() का उपयोग करना होगा। जैसे ही वे कहीं और नहीं खोले जाते हैं, वे विंडोज़ द्वारा हटा दिए जाएंगे। तो आप एक रैपर लिख सकते हैं जो इसे हटाने के बजाय CloseHandle() को कॉल करता है। आप अपनी खुद की स्मार्टपॉइंटर क्लास भी लिख सकते हैं जो बेहतर हो सकता है क्योंकि अब एक रैपर की आवश्यकता नहीं है।

1

आप एक डिलीटर क्लास बना सकते हैं जो हटाए जाने के बजाय हैंडल को छोड़ देगा()।

आप इस LINK कैसे वे एक shared_ptr के साथ हटाने सरणियों समाधान कर लिया है में देख सकते हैं

struct handle_deleter 
    { 
    void operator()(HANDLE handle) 
     { CloseHandle(p); } 
    }; 

    HANDLE blah = GetSomeHandle(); 
    unique_ptr myPointer(blah,handle_deleter); 
2

आप एक कस्टम Deleter

struct handle_deleter 
{ 
    void operator()(void* handle) 
    { 
     if(handle != nullptr) 
      CloseHandle(handle); 
    } 
}; 

typedef std::unique_ptr<void, handle_deleter> UniqueHandle_t; 
UniqueHandle_t ptr(CreateFile(...)); 
1

मैं हैंडल के साथ स्मार्ट संकेत उपयोग करने की अनुशंसा नहीं है के साथ अपने unique_ptr typedef कर सकते हैं।

मैं आपको A Proposal to Add additional RAII Wrappers to the Standard Library और the drawbacks of using smart pointers with handles पर एक नज़र डालने की सलाह देता हूं।

व्यक्तिगत रूप से, मैं इन स्थितियों के लिए std::unique_ptr का उपयोग करने के बजाय उस प्रस्ताव के संदर्भ कार्यान्वयन का उपयोग कर रहा हूं।

1

अभी तक एक और समाधान

std::unique_ptr< void, void(*)(HANDLE) > uniqueHandle(file, [](HANDLE h) { ::CloseHandle(h); }); 
1

अलेक्जेंडर Drichel के समाधान से प्रेरित है, यहाँ भी कम है

std::unique_ptr< HANDLE, decltype(&CloseHandle) > uniqueHandle(nullptr, CloseHandle); 

में MSVC 2010 नोट वर्क्स है कि आप में समारोह नाम के लिए '&' निर्दिष्ट करने की आवश्यकता पॉइंटर-टू-फ़ंक्शन प्रकार को कम करने के लिए decltype()।

1

एक हैंडल हमेशा CloseHandle() से सावधान नहीं है, सावधान रहें। उदाहरण के लिए FindNextFile() के साथ खोला गया एक हैंडल FindClose() द्वारा बंद होना चाहिए।

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