2015-12-06 7 views
16

मुक्त नहीं किया जाना चाहिए वर्तमान में मैं ग्लिब लाइब्रेरी से कुछ फ़ंक्शंस का उपयोग कर रहा हूं। ग्लिब के साथ भी जीओ आता है। ग्लिब एक सी लाइब्रेरी है और इसलिए मुझे कुछ संरचनाएं हटाने की ज़रूरत है जो मैं बनाता हूं।एक साझाकर्ता के साथ एक पॉइंटर के साथ share_ptr का उपयोग कैसे करें जिसे

वस्तुओं मैं बनाने के एक smartpointer जैसे से कई के लिए:

std::shared_ptr<GAsyncQueue> my_queue = std::shared_ptr<GAsyncQueue>(g_async_queue_create(), g_async_queue_unref); 

इसके लिए एक GAsyncQueue करने के लिए एक साझा सूचक बनाता है और यह सुरक्षित रूप से अपने जीवन के अपने अंत पर कतार नष्ट कर देता है है।

हालांकि, मुझे समस्या है जब मैं जीओ लाइब्रेरी से एक पॉइंटर प्राप्त करता हूं जिसे मुझे मुक्त नहीं करना चाहिए। निम्नलिखित कोड my_connection में एक GSocketClient wich उपकरण (ग्लिब बोलने में) GIOStream है।

std::shared_ptr<GInputStream> my_input_stream = 
    std::shared_ptr<GInputStream> (
     g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get())) 
    ); 

क्योंकि GIOStream पर दस्तावेजीकरण का उल्लेख है, कि सूचक g_io_stream_get_input_stream() के साथ प्राप्त मुक्त नहीं किया जाना चाहिए। ऐसा इसलिए है क्योंकि यह my_connection उदाहरण के स्वामित्व में है। मैंने नष्ट ऑब्जेक्ट के लिए लैम्डा बनाने के बारे में सोचा, साझा पॉइंटर ऑब्जेक्ट का दूसरा पैरामीटर। उदाहरण के लिए auto deleter = [](GInputStream* ptr) {}; और उसके बाद उस लैम्ब्डा को साझा पॉइंटर पर फ़ंक्शन फेंक दें, लेकिन यह एक प्रकार का बेवकूफ लगता है।

+3

क्यों एक (स्मार्ट) पॉइंटर का उपयोग करें? एक संदर्भ पर्याप्त नहीं होगा? – edmz

+0

@black मैं अभी भी इसके बारे में थोड़ा चिंतित हूं। इनपुट स्ट्रीम एक ऑब्जेक्ट का एक उदाहरण है जो कॉपी हो जाता है। आखिरी प्रति विनाशक कहलाता है जब GIOStream नष्ट हो जाता है। शायद चूंकि मुझे इसे नष्ट करने की ज़रूरत नहीं है, वैसे भी एक सादा पुराना सूचक भी ठीक है ... – hetepeperfan

+0

और एक पॉइंटर मैं नल पर सेट कर सकता हूं, फिर यह देखना आसान है कि यह प्रारंभ किया गया है या नहीं। – hetepeperfan

उत्तर

12

ठीक है, कोई-op Deleter करने के लिए वैकल्पिक का उपयोग कर किया जा सकता है aliasing साझा सूचक

template <class U> shared_ptr (const shared_ptr<U>& x, element_type* p) noexcept; 

यह शेयरों x, लेकिन प्राप्त करने के बाद() तुम वापस p मिलेगा।

चर्चा: What is shared_ptr's aliasing constructor for?

5

आपको लगता है कि कुछ नहीं करता है एक Deleter प्रकार का उपयोग कर सकते हैं, लेकिन यह shared_ptr के निर्माता

struct DoNothing { 
    template <typename T> 
    void operator()(T*) const noexcept { } 
}; 

लिए एक तर्क के रूप में पारित करने की आवश्यकता होगी जब एक shared_ptr बनाने आप इन deleters में से एक बनाने की आवश्यकता होगी और इसे कन्स्ट्रक्टर में पास करें (जैसा कि आप लैम्ब्डा के साथ कर रहे हैं)। आप एक मध्यवर्ती समारोह

template <typename T> 
std::shared_ptr<T> non_deleting_shared_ptr(T* ptr) { 
    return {ptr, DoNothing}; 
} 

auto my_input_stream = 
    non_deleting_shared_ptr(
     g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get())); 

साथ अपने आप पर यह आसान बनाने के कर सकते हैं हालांकि बड़ा सवाल यह है कि क्यों आप स्मार्ट संकेत दिए गए हैं जब आप स्वामित्व इसे का एक हिस्सा होने के लिए नहीं करना चाहते हैं का उपयोग कर रहे हैं। आप लगभग GAsyncQueue* के साथ लगभग निश्चित रूप से बेहतर हो जाएंगे, बशर्ते कि आप ऐसी स्थिति में हों जहां आपके पास shared_ptr है, जिसे कभी-कभी मुक्त करने की आवश्यकता होती है। डेटा सदस्य की तरह शायद?

6

आप शायद सिर्फ एक std::shared_ptr जरूरत नहीं है। और आपको शायद एक सूचक की भी आवश्यकता नहीं है।

जैसा कि मैंने अपने प्रश्न और टिप्पणियाँ पढ़ने, मैं

auto& my_input_stream = *(g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get()))) 

ऐसा नहीं है कि संकेत दिए गए वैकल्पिक डेटा की अनुमति सच है के खिलाफ किसी भी बिंदु नहीं दिख रहा। हालांकि, यह भी सच है कि यह ज्यादातर गलत तरीके से उपयोग किया जाता है।

void foo(type* ptr) 
{ 
    if (!ptr) 
     throw exception; 
} 

अक्सर समझ में नहीं आता है। यदि फ़ंक्शन को ठोस डेटा पर काम करना है, तो एक पूर्ण पैरामीटर केवल तभी उपयोगी होता है जब आप उस डेटा को प्रदान करने के बारे में चिंता करते हैं।अन्यथा, ऑब्जेक्ट में केवल एक संदर्भ (संभवतः const) की आवश्यकता है।

स्मार्ट पॉइंटर्स उपयोगी हैं; लेकिन वे अभी भी पॉइंटर्स हैं। यदि संभव हो, तो उन्हें पूरी तरह से टालना, और भी बेहतर है।


टिप्पणियों से:

हालांकि, एक संदर्भ हमेशा

बिल्कुल प्रारंभ किया जाना चाहिए। सी ++ 11 के बाद से हमें std::reference_wrapper मिल गया है जिसे कंटेनरों में भी पुन: एकत्रित और संग्रहीत किया जा सकता है।

+0

मेरे प्रश्न के आधार पर आप सही हैं। हालांकि, एक संदर्भ हमेशा प्रारंभ किया जाना चाहिए। चूंकि my_input_stream एक वर्ग सदस्य है (जो मेरे प्रश्न में नहीं दिखाया गया है) जो खोला नहीं गया है। मैं इसे केवल तभी सेट कर सकता हूं जब मैं वास्तव में सॉकेट कनेक्शन खोलूं। लेकिन मैं इसे किसी भी तरह से उखाड़ फेंक दूंगा क्योंकि यह अन्य पाठकों के लिए एक अच्छा जवाब है। – hetepeperfan

+0

@hetepeperfan True। देखें कि मेरा अपडेट उसको संबोधित कर सकता है;) – edmz

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