2016-02-09 17 views
5

मैं एक सामान्य वर्ग कि कुछ इस तरह दिखता है। विशेष रूप से, T किसी भी प्रकार का है, इसलिए यह स्टैक पर आवंटित स्मृति हो सकती है (जो हमेशा Example के लिए नो-तर्क कन्स्ट्रक्टर के माध्यम से बनाया गया है) या ढेर पर।हटाया जा रहा है एक खाका प्रकार

उदाहरण के लिए, ग्राहक T एक int* के लिए प्रकार बनाता है और गतिशील स्मृति के लिए सूचक, मैं कैसे के रूप में यदि ग्राहक int के प्रकार सेट करने के लिए विरोध data पर delete कॉल करने के लिए पता है प्रदान करता है तो क्या होगा?

+3

ठीक है आप मानक कंटेनर की तरह हो सकते हैं और ऐसा नहीं कर सकते हैं। मानक कंटेनर विनाशक तत्वों के लिए कुछ भी नहीं करेंगे यदि प्रकार एक सूचक प्रकार है। – NathanOliver

+0

संकेत: 'std :: is_pointer ' के आस-पास स्थित एक सीआरटीपी नीति प्रकार मुहावरे का उपयोग करें। इसे मज़ेदार बनाने के लिए, फिर पूरी चीज को बिन करें क्योंकि यह वास्तव में * बिंदुओं को गतिशील लोगों से स्वचालित चर के लिए बिंदुओं को अलग करने के लिए मुश्किल है। – Bathsheba

+0

दोनों वैध अंक। मैं उस पर काम कर रहा हूं जिसे मैं अधिक व्यायाम करने के लिए विचार करता हूं, इसलिए मैं अंततः सोच रहा था कि क्या मुझे कुछ याद आ रहा था, या अगर सामान्य रूप से काम करना मुश्किल था (जो मामला प्रतीत होता है) – nmagerko

उत्तर

7

सबसे सरल जवाब है: नहीं। उपयोगकर्ता को दूसरे अनुमान लगाने की कोशिश न करें और ऐसा कुछ करें जो वे उम्मीद नहीं कर सकते हैं। मानक कंटेनर के समान नीति को अपनाना: मान लें कि T स्वयं ठीक से बाद में साफ हो जाता है।

यदि ग्राहक कोड सही ढंग से लिखा गया है, तो यह स्मृति और अन्य संसाधनों के स्वचालित और सही प्रबंधन के लिए आरएआईआई कक्षाओं (जैसे स्मार्ट पॉइंटर्स) का उपयोग करेगा। यदि ऐसा नहीं है, तो आप अपने प्रदाता कोड में इसे ठीक करने की उम्मीद नहीं कर सकते हैं।

अपनी कक्षा std::unique_ptr और std::shared_ptr के साथ-साथ किसी भी अन्य कस्टम आरएआईआई कक्षा के साथ काम करें, और अपने ग्राहकों को प्रबंधन स्वयं करने दें। क्या होगा यदि वे गैर-मालिक पॉइंटर्स को स्टोर करना चाहते हैं, आखिरकार?

+0

पर्याप्त मेला - क्लाइंट बनाम क्लीनअप का प्रबंधन करने की अस्पष्टता वास्तव में मुझे चिंतित थी। – nmagerko

2

आप टेम्पलेट विशेषज्ञता का उपयोग कर सकते हैं।

template <class T> 
class Example 
{ 
    private: 
    T data; 
    public: 
    Example() 
     : data(T()) 
    {} 

    Example(T typeData): data(typeData) 
    {} 
}; 

template <class T> 
class Example<T*> 
{ 
    private: 
    T* data; 
    public: 
    Example() : data(nullptr){} 
    Example(T* typeData): data(typeData) {} 
    ~Example() 
    { 
     delete data; 
    } 
}; 

int main() 
{ 
    Example<int> e; 
    Example<int*> e2; 

    return 0; 
} 
+1

कूल पैटर्न इस तरह व्यवहार व्यवहार करने के लिए बहुत आसान है। – nmagerko

+1

मैं उत्पादन कोड में इसका उपयोग करने के बारे में सावधान रहूंगा। जैसा कि अन्य ने कहा है: यह कहना मुश्किल है कि कोई सूचक 'नए' भंडारण को इंगित करता है या नहीं। –

0

आप मानक लाइब्रेरी की तरह इसके बारे में चिंता नहीं कर सकते हैं। उदाहरण के लिए, यदि आप पॉइंटर्स का वेक्टर बनाते हैं तो आप वेक्टर को दायरे से बाहर जाने से पहले उन्हें हटाने के लिए ज़िम्मेदार होते हैं। लोग तब तय कर सकते हैं कि वे इसे भी हटाना चाहते हैं (शायद यह सॉर्ट करने के लिए अस्थायी है और कुछ और वस्तु का मालिक है)। वे स्मार्ट पॉइंटर्स का भी उपयोग कर सकते हैं ताकि वेक्टर पॉइंटर के लिए विनाशक के माध्यम से ऑब्जेक्ट को नष्ट कर सकें।

इस मामले में, कम है। आपको कुछ भी जटिल नहीं करना है। आपको टेम्पलेट के कई संस्करणों को बनाए रखने की आवश्यकता नहीं है। अंत में, आपके टेम्पलेट के उपयोगकर्ता के पास अधिक नियंत्रण है ... और ज़िम्मेदारी भी।

0

मैं सुझाव है कि आप T के लिए std::unique_ptr उपयोग करने के लिए जब आप Example जरूरत है एक मालिक सूचक धारण करने के लिए। यदि T एक कच्चा सूचक है, तो यह बस स्वामित्व में नहीं है और इसे हटा नहीं देना चाहिए।

यदि आपको पॉइंटर प्रारंभ करने के लिए Example की आवश्यकता है, तो इसे std::unique_ptr के लिए विशेषज्ञ बनाएं और डिफ़ॉल्ट निर्माता में std::make_unique पर कॉल करें।

template<typename T> 
class Example<std::unique_ptr<T>> { 
    Example() : data{std::make_unique<T>()} {} 

    /* rest of the class */ 
}; 

आप ऐसा करते हैं, तो आप अपने वर्ग T* के लिए एक new करने के लिए विशेषज्ञ नहीं करना चाहिए, जैसा कि आप गैर मालिक संकेत आरंभ नहीं कर सकते। आपको इसे कन्स्ट्रक्टर में प्राप्त करना चाहिए, और यदि आप इसे शून्य नहीं करना चाहते हैं तो कच्चे पॉइंटर्स के लिए डिफ़ॉल्ट कन्स्ट्रक्टर को अक्षम कर सकते हैं।

template<typename T> 
class Example<T*> { 
    Example() = delete; 
    Example(T* data_) : data{data_} 

    /* data is not an owning pointer. No need for a destructor */ 

    /* rest of the class */ 
}; 

यदि आप उन नियमों का पालन करते हैं, तो आपको स्मृति प्रबंधन में कोई समस्या नहीं होनी चाहिए।

0

मेमोरी रिलीज सहायक टेम्पलेट कक्षाओं का उपयोग करें जिसे टाइप करके चुना जा सकता है। आपको टेम्पलेट विशेषज्ञता के साथ अपनी कक्षा का गणराज्य बनाने की आवश्यकता नहीं है। आप केवल एक कक्षा लिख ​​सकते हैं।

#include <type_traits> 

template<typename T> // primary template 
struct Releaser 
{ 
    template<typename V> 
    void release(V v) { } 
}; 
template<> // explicit specialization for T = std::true_type 
struct Releaser<std::true_type> 
{ 
    template<typename V> 
    void release(V v) { delete[] v; } 
}; 

template <class T> 
class Example 
{ 
    private: 
    T data; 
    public: 
    Example(): data(T()) {} 
    Example(T typeData): data(typeData) {} 
    typedef typename std::is_pointer<T>::value_type isptr_type; 
    ~Example() { 
     Releaser<isptr_type>::release(data); 
    } 
}; 

लेकिन नए कॉल के रूप में जानने की आवश्यकता है, इसलिए हटाएं या हटाएं [] का उपयोग करें।

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