मेरे पास MyClass नामक एक वर्ग है, जिसमें किसी वस्तु के लिए एक संकेतक होता है, जैसे:

class MyClass {
public:
    MyClass() : _blob(nullptr) {}
    ~MyClass() { free(); }

    void generate() {
        if(!_blob)
            _blob = new Blob;
    }

    void free() {
        if(_blob) {
            delete _blob;
            _blob = nullptr;
        }
    }

    Blob* getBlob() { return _blob; }

private:
    Blob *_blob;
};

इसका कारण यह है कि यह एक ढेर आवंटित ऑब्जेक्ट के लिए एक संकेतक रखता है और इसे स्टैक पर नहीं रखता है क्योंकि कुछ MyClass इंस्टेंस इस ऑब्जेक्ट के लिए डेटा आवंटित नहीं करते हैं, इसलिए इसे एक्सेस करने से पहले मुझे यह जांचने की आवश्यकता है कि क्या यह नहीं है एक अशक्त सूचक:

if(myClass->getBlob())
    myClass->getBlob()->doSomething();

अब मेरे पास _hasBlob नामक बूल वेरिएबल को स्टोर करने का विचार था और फिर इसे इस तरह से उपयोग करें

if(myClass->hasBlob())
    myClass->getBlob()->doSomething();

क्या यह तेज और वैध माना जाता है? या इसे बुरा व्यवहार माना जाता है क्योंकि मैं किसी भी तरह से डेलीफरिंग को समाप्त करने के खतरे को देख सकता हूं।

3
Pilpel 26 नवम्बर 2015, 15:23

2 जवाब

सबसे बढ़िया उत्तर

यह कानूनी लेकिन बेमानी है। यह तेज नहीं है। वास्तव में, जबकि चेक खुद ही तेज है, सूचक की वैधता के साथ सिंक में बूलियन को बनाए रखना मामूली धीमा है। इसके बारे में सबसे बुरी बात यह साबित करना है कि बूलियन हमेशा सिंक में है। एक बार जब यह लागू हो जाता है और सही साबित हो जाता है, तो यह सिर्फ बेमानी और स्मृति की बर्बादी है।

7
eerorika 26 नवम्बर 2015, 13:44

सामान्य तौर पर, आप MyClass::getBlob() से अपेक्षा करेंगे कि जब भी आप इसके लिए कहेंगे, आपको हमेशा एक मान्य वस्तु प्रदान करेगा। तो सामान्य तौर पर मेरा सुझाव इस तरीके को लागू करना होगा:

Blob* getBlob() { 
  if(_blob == nullptr) { 
     _blob = new Blob; 
     // Or call private method generateBlob, if there is a lot of logic
  }

  return _blob; 
}

वैकल्पिक रूप से, यदि डिफॉल्ट-निर्मित Blob छोटे हैं और आपके पास MyClass इंस्टेंसेस नहीं हैं, तो आप कंस्ट्रक्टर में Blob ऑब्जेक्ट बना सकते हैं और getBlob एक संदर्भ लौटाएं, ताकि आपके पास वैध MyClass ऑब्जेक्ट होने के बाद आपको कभी नहीं कुछ भी जांचना पड़े।

यदि आप Blob ऑब्जेक्ट्स के इस स्वचालित निर्माण से बचना चाहते हैं, तो आप hasBlob चेक जोड़ सकते हैं, लेकिन एक अलग बूलियन रखने के बजाय, मैं इसे लागू करूंगा

bool hasBlob() const { return _blob != nullptr; }

यह फ़ंक्शन इनलाइन होना लगभग तय है, आपको किसी भी अतिरिक्त भंडारण की लागत नहीं है, और यह सही परिणाम की गारंटी देता है (उदाहरण के लिए, ऐसा कभी नहीं हो सकता है कि आप _hasBlob = true सेट करें और फिर {{X1} आवंटित करने में विफल रहें। })। जैसा कि आप कहते हैं, अभी भी एक शून्य सूचक को निष्क्रिय करने का जोखिम है, लेकिन जैसा कि आपने स्पष्ट रूप से प्रलेखित किया है (उम्मीद है) कि getBlob इस संकेत के लिए कोई बूँद आवंटित नहीं होने पर अशक्त सूचक वापस कर सकता है, जो अब जोखिम के साथ है फोन करने वाले और उन्हें परिणाम की जांच करने के लिए ध्यान रखना चाहिए, क्योंकि किसी भी फ़ंक्शन के साथ एक पॉइंटर वापस आ रहा है। वास्तव में, यह समाधान आपके पास पहले से मौजूद कोड के बराबर है, क्योंकि if(myObject->getBlob()) अब बिल्कुल if(myObject->hasBlob()) के समान जांच करता है - केवल अंतर यह है कि शायद बाद वाला थोड़ा अधिक स्व-दस्तावेज है ।

चूंकि आप टिप्पणियों में इंगित करते हैं कि आप प्रदर्शन के बारे में चिंतित हैं: मुझे संदेह है कि null के खिलाफ एक संकेतक की जांच करना काफी तेज है, लेकिन हमेशा की तरह, यदि आप सुनिश्चित होना चाहते हैं, तो सामान्य सलाह "इसे मापें!" आयोजित करता है। उदाहरण के लिए, आप पा सकते हैं कि getBlob के मेरे पहले संस्करण में अतिरिक्त जांच के कारण कंपाइलर फ़ंक्शन को इनलाइन नहीं करेगा।

4
CompuChip 26 नवम्बर 2015, 12:42