2009-10-13 6 views
9

के साथ shared_ptr का उपयोग करके एक हैंडल राय-अनुपालन बनाना मैंने हाल ही में SO पर RAII के बारे में एक सामान्य प्रश्न पोस्ट किया है। हालांकि, मेरे पास अभी भी मेरे हैंडल उदाहरण के साथ कुछ कार्यान्वयन समस्याएं हैं।कस्टम डिलीटर

HANDLEvoid *windows.h में टाइप किया गया है। इसलिए, सही shared_ptr परिभाषा

std::tr1::shared_ptr<void> myHandle (INVALID_HANDLE_VALUE, CloseHandle); 

उदाहरण 1CreateToolhelp32Snapshot होने की जरूरत है: HANDLE और काम करता है देता है।

const std::tr1::shared_ptr<void> h 
    (CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL), CloseHandle); 

मैं परिभाषा (सही तरीका है क्या?) समस्याओं, पर जाना जब मैं कुछ और WinAPI इस सूचक के साथ आदेशों कॉल करने के लिए कोशिश में void का उपयोग करते हैं। वे कार्यात्मक रूप से काम करते हैं, लेकिन बदसूरत हैं और मुझे यकीन है कि एक बेहतर समाधान होना चाहिए।

निम्नलिखित उदाहरणों में, h एक सूचक है जो शीर्ष पर परिभाषा के माध्यम से बनाया गया था।

उदाहरण 2OpenProcessToken: अंतिम तर्क PHANDLE है। कास्ट के साथ मध्यम बदसूरत।

OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 
    (PHANDLE)&h); 

उदाहरण 3Process32First: पहला तर्क एक HANDLE है। वास्तव में बदसूरत।

Process32First(*((PHANDLE)&h), &pEntry); 

उदाहरण 4 एक निरंतर HANDLE के साथ सरल तुलना। वास्तव में बदसूरत।

if (*((PHANDLE)&h) == INVALID_HANDLE) { /* do something */ } 

हैंडल के लिए उचित साझा_प्टर बनाने का सही तरीका क्या है?

उत्तर

9

उदाहरण 1 ठीक है

उदाहरण 2 गलत है। अंधेरे से फाउंडल को कास्टिंग करके, shared_ptr तर्क को छोड़ दिया जाता है। यह बजाय कुछ इस तरह होना चाहिए:

HANDLE h; 
OpenProcessToken(...., &h); 
shared_ptr<void> safe_h(h, &::CloseHandle); 

या, एक पूर्व exising shared_ptr के लिए आवंटित करने के लिए:

shared_ptr<void> safe_h = .... 
{ 
    HANDLE h; 
    OpenProcessToken(...., &h); 
    safe_h.reset(h, &::CloseHandle); 
}//For extra safety, limit visibility of the naked handle 

या, अपनी खुद की, सुरक्षित, OpenProcessToken की है कि एक साझा संभाल रिटर्न बजाय संस्करण बनाने एक ब्रांड लेने का:

// Using SharedHandle defined at the end of this post 
SharedHandle OpenProcess(....) 
{ 
    HANDLE h = INVALID_HANDLE_VALUE; 
    ::OpenProcessToken(...., &h); 
    return SharedHandle(h); 
} 

उदाहरण 3: इन चक्कर लगाने की कोई आवश्यकता नहीं है।यह ठीक किया जाना चाहिए:

Process32First(h.get(), ...); 

उदाहरण 4: फिर से, कोई चक्कर:

if (h.get() == INVALID_HANDLE){...} 

चीजें अच्छे बनाने के लिए, आप की तरह कुछ typedef सकता है: बेहतर अभी तक

typedef shared_ptr<void> SharedHandle; 

या, यदि सभी हैंडल को CloseHandle() के साथ बंद करना है, एक साझा किया गया हैडल क्लास एक shared_ptr को लपेटना और स्वचालित रूप से सही डिलीटर प्रदान करना:

// Warning: Not tested. For illustration purposes only 
class SharedHandle 
{ 
public: 
    explicit SharedHandle(HANDLE h) : m_Handle(h, &::CloseHandle){}; 
    HANDLE get()const{return m_Handle.get();} 

    //Expose other shared_ptr-like methods as needed 
    //... 

private: 
    shared_ptr<void> m_Handle; 
}; 
+0

क्या आपके पहले उदाहरण 2 कोड स्निपेट में इसे सुरक्षित करने के बाद असुरक्षित 'हैंडल' को हटाने की संभावना है? – Etan

+0

आप OpenProcessHandle() को एक फ़ंक्शन रैपिंग बना सकते हैं (मैंने इसे पोस्ट में जोड़ा है) या दूसरे स्निपेट की तुलना में वही काम करते हैं, साझा_h INVALID_HANDLE_VALUE –

1

यहाँ मेरी विकल्प है, जो काफी अच्छा छोड़कर आप हमेशा .get() के बाद भिन्नता की जरूरत है और एक functor या लैम्ब्डा की आवश्यकता है पर एक नज़र डालें:

template<typename HandleType, typename Deleter> 
std::shared_ptr<HandleType> make_shared_handle(HandleType _handle, Deleter _dx) 
{ 
    return std::shared_ptr<HandleType>(new HandleType(_handle), _dx); 
} 

तो:

auto closeHandleDeleter = [](HANDLE* h) { ::CloseHandle(*h); }; 
std::shared_ptr<HANDLE> sp = make_shared_handle(a_HANDLE, closeHandleDeleter); 
f_that_takes_handle(*sp.get()); 

मुझे इस बारे में सबसे ज्यादा पसंद है कि इस तक पहुंचने के लिए कोई अतिरिक्त काम नहीं है:

std::weak_ptr<HANDLE> wp = sp; // Yes. This could make sense in some designs. 

और निश्चित रूप से, सहायक कार्य किसी भी हैंडल प्रकार की पसंद के साथ काम करता है।

3

इसके लिए shared_ptr से परेशान न करें, ATL :: CHandle का उपयोग करें।

यहाँ कारण है कि:

  • जब आप CHandle देख आप जानते हैं कि यह एक संभाल के लिए एक आरए II आवरण है।
  • जब आप shared_ptr<void> देखते हैं तो आप नहीं जानते कि यह क्या है।
  • CHandle स्वामित्व साझा नहीं करता है (हालांकि कुछ मामलों में आप एक साझा स्वामित्व चाहते हैं)।
  • CHandle विंडोज़ विकास ढेर के लिए एक मानक है।
  • CHandle कस्टम डिलीटर (कम टाइपिंग/रीडिंग) के साथ shared_ptr<void> से अधिक कॉम्पैक्ट है।
+0

में आरंभ किया गया है क्या आप उस पर विस्तार कर सकते हैं? [प्रलेखन] (https://msdn.microsoft.com/en-us/library/5fc6ft2t.aspx) बहुत कुछ नहीं कहता है, लेकिन यह एक अद्वितीय_ptr की तरह दिखता है, मुझे नहीं लगता कि चैंडल साझा करने की सुविधा कैसे देता है। – phant0m

+0

@ phant0m चंडल साझा स्वामित्व प्रदान नहीं करता है। –