2013-02-08 26 views
5

जब मैं किसी सी ++ 11 लैम्ब्डा में संदर्भ द्वारा किसी ऑब्जेक्ट को कैप्चर करता हूं, तो ऑब्जेक्ट को दायरे से बाहर जाने दें, और फिर लैम्ब्डा को निष्पादित करें, फिर भी ऑब्जेक्ट तक पहुंच हो। जब मैं निम्नलिखित कोड निष्पादित करता हूं, तो लैम्ब्डा कॉल अभी भी ऑब्जेक्ट तक पहुंच सकता है, हालांकि विनाशक को पहले ही बुलाया जा चुका है! क्या कोई यह समझा सकता है कि यह क्यों काम करता है और मुझे रनटाइम त्रुटि क्यों नहीं मिलती?लैम्ब्डा कैप्चर एंड मेमोरी मैनेजमेंट

MyClass created! 
MyClass destroyed! 
5 
has enough health 
+3

मुझे संदेह है कि यह अनिर्धारित व्यवहार है, और इस मामले में कि अनिर्धारित व्यवहार सिर्फ "वस्तु जीवित और अच्छी तरह से प्रतीत होती है।" – templatetypedef

+1

अपरिभाषित व्यवहार। Http://c-faq.com/ansi/experiment.html –

+0

देखें यदि आप इसे स्मृति रिसाव विश्लेषक (जैसे वालग्रिंड) के माध्यम से चलाते हैं, तो यह (उम्मीद है) रिपोर्ट करेगा कि आप किसी मृत वस्तु तक पहुंच रहे हैं। –

उत्तर

17

अनुसार झूलने संदर्भ

एक इकाई संदर्भ द्वारा कब्जा कर लिया गया है, तो परोक्ष या स्पष्ट करने के लिए the cppreference.com website's documentation of lambda functions

, और समारोह:

#include <iostream> 

class MyClass { 
public: 
    int health = 5; 
    MyClass() {std::cout << "MyClass created!\n";} 
    ~MyClass() {std::cout << "MyClass destroyed!\n";} 
}; 

int main(int argc, const char * argv[]) 
{ 
    std::function<bool (int)> checkHealth; 
    if(true) { 
     MyClass myVanishingObject; 
     checkHealth = [&myVanishingObject] (int minimumHealth) -> bool { 
      std::cout << myVanishingObject.health << std::endl; 
      return myVanishingObject.health >= minimumHealth; 
     }; 
    } // myVanishingObject goes out of scope 

    // let's do something with the callback to test if myVanishingObject still exists. 
    if(checkHealth(4)) { 
     std::cout << "has enough health\n"; 
    } else { 
     std::cout << "doesn't have enough health\n"; 
    } 
    return 0; 
} 

यहाँ उत्पादन है बंद करने की वस्तु के कॉल ऑपरेटर का आह्वान किया जाता है डी के अस्तित्व के जीवनकाल समाप्त होने के बाद, अपरिभाषित व्यवहार होता है। सी ++ बंद कैप्चर किए गए संदर्भों के जीवनकाल का विस्तार नहीं करते हैं।

दूसरे शब्दों में, तथ्य यह है कि आप संदर्भ द्वारा वस्तु पर कब्जा कर लिया है और फिर वस्तु के जीवनकाल समाप्त होता है जाने का मतलब है कि लैम्ब्डा लागू अपरिभाषित व्यवहार का कारण बनता है। चूंकि यूबी काम कर सकता है एक संभावित तरीका यह है कि "वस्तु जीवित और अच्छी तरह से प्रतीत होती है, भले ही वस्तु मर गई हो," मुझे संदेह है कि आप अपरिभाषित व्यवहार को खुद को प्रकट कर रहे हैं क्योंकि कुछ भी गलत नहीं हुआ है।

मुझे संदेह है कि यह मामला होगा यदि कंपाइलर अस्थायी चर के लिए एक अद्वितीय स्टैक स्थान आवंटित करता है। इसका मतलब यह होगा कि ऑब्जेक्ट के जीवनकाल के बाद main रिटर्न से पहले, स्मृति किसी भी चीज़ से छू नहीं जाएगी। तदनुसार, आप वैरिएबल 5 वैल्यू को पहले से ही देख रहे होंगे, क्योंकि इसके अलावा कुछ और नहीं लिखा जा रहा है।

आशा है कि इससे मदद मिलती है!

+0

तो इसे संभालने का एक अच्छा तरीका क्या होगा? मेरा सुझाव है कि myVanishingObject (स्टैक पर उदाहरण के बजाए) में shared_ptr बनाना है, और उस share_ptr को मान द्वारा कैप्चर करें। तुम क्या सोचते हो? – basteln

+1

@ basteln- यह सही समझ में आता है - आप चाहते हैं कि ऑब्जेक्ट उस क्षेत्र से आगे बनी रहें जिसमें इसे बनाया गया है, इसलिए इसे उचित रूप से ढेर करना और मेमोरी प्रबंधन को संभालने के लिए 'shared_ptr' का उपयोग करना उचित है। मूल्य के आधार पर पॉइंटर को कैप्चर करना सुनिश्चित करें! – templatetypedef

+0

ठीक है, आपका उत्तर अच्छा है लेकिन हम इस समस्या को कैसे हल कर सकते हैं? Obj-C और Lambdas द्वारा कब्जा कर लिया गया स्विफ्ट ऑब्जेक्ट में रखा जाता है (संदर्भ काउंटर बढ़ता है) और लैम्ब्डा जारी होने के बाद जारी किया जाता है – fnc12