2012-09-20 21 views
12

मान लें कि मेरे पास दो स्थानीय स्मार्ट पॉइंटर्स हैं, foo और barसी ++ 11: लैम्बडा कैप्चर किस आदेश में नष्ट हो गया है?

shared_ptr<Foo> foo = ... 
shared_ptr<Bar> bar = ... 

ये स्मार्ट संकेत दिए गए संसाधनों के आसपास रैपर कि किसी कारण से आदेश foo, तो bar में विलुप्त किया जाना चाहिए।

अब मैं एक लैम्ब्डा बनाना चाहता हूं जो foo और bar का उपयोग करता है, लेकिन इसमें शामिल दायरे से बाहर निकलता है। इसलिए मैं, मान द्वारा उनमें कब्जा था इस तरह:

auto lambda = [foo, bar]() { ... }; 

इस समारोह वस्तु के भीतर foo और bar की प्रतियां बनाता है। जब फ़ंक्शन ऑब्जेक्ट को नष्ट कर दिया जाता है, तो इन प्रतियों को भी नष्ट कर दिया जाएगा, लेकिन मुझे उस क्रम के बारे में परवाह है जिसमें यह होता है। तो मेरा सवाल है:

जब एक लैम्ब्डा ऑब्जेक्ट नष्ट हो जाता है, तो इसके द्वारा मूल्यवान मूल्यों को किस क्रम में नष्ट किया जाता है? और मैं इस उम्मीद को कैसे प्रभावित कर सकता हूं?

+4

मुझे लगता है कि यह भी विचार करने के लिए दिलचस्प हो जाएगा '[=]'। –

+0

@ आर। मार्टिनिन्हो फर्नांडीस: '[foo, bar]' '[= foo, = bar] 'के बराबर है, यानी यह एक प्रति है। –

+0

@ डेविड: मुझे लगता है कि उनका शाब्दिक अर्थ था '[=]', यानी विचार करें कि घोषणापत्र आदेश किसी के स्वयं को सूचीबद्ध किए बिना क्या होगा। (स्पष्ट रूप से यह अब एक महत्वपूर्ण मुद्दा है क्योंकि घोषणापत्र आदेश कैप्चर करने के तरीके के बावजूद घोषणा आदेश निर्दिष्ट नहीं है।) – ildjarn

उत्तर

15

spec इसमें शामिल है ... प्रकार। 5.1.2 से, पैरा 14:

एक इकाई प्रतिलिपि द्वारा कब्जा कर लिया है अगर यह परोक्ष कब्जा कर लिया है और कब्जा-डिफ़ॉल्ट है = या अगर यह स्पष्ट रूप से एक पर कब्जा के साथ कब्जा कर लिया है एक & शामिल नहीं है कि। प्रतिलिपि द्वारा कब्जा कर लिया गया प्रत्येक इकाई के लिए, बंद नाम में एक अज्ञात गैर स्थैतिक डेटा सदस्य घोषित किया जाता है। इन सदस्यों की घोषणा आदेश अनिर्दिष्ट है।

जोर जोड़ा गया। क्योंकि घोषणा आदेश निर्दिष्ट नहीं है, निर्माण आदेश अनिर्दिष्ट है (क्योंकि निर्माण का आदेश घोषणा के आदेश के समान है)। और इसलिए, विनाश आदेश अनिर्दिष्ट है, क्योंकि विनाश का आदेश निर्माण के आदेश के विपरीत है।

संक्षेप में, यदि आपको घोषणा आदेश (और विभिन्न निर्माण/विनाश आदेश जो इसके प्रमुख हैं) की परवाह करने की आवश्यकता है, तो आप एक लैम्ब्डा का उपयोग नहीं कर सकते हैं। आपको अपना खुद का प्रकार बनाना होगा।

+1

यह आपके लैम्बडा के अंत में साझा पॉइंटर्स में से किसी एक को रीसेट नहीं कर सका, ताकि यह सुनिश्चित किया जा सके कि यह इसके संसाधन को जारी करता है विनाश के दौरान? –

+0

कभी नहीं; मेरा जवाब देखें काम करने के लिए लैम्ब्डा को उत्परिवर्तनीय होना चाहिए। –

+0

@ निकोल: स्पष्टीकरण के लिए धन्यवाद। मैं थोड़ी परेशान हूं कि उन्होंने आदेश निर्दिष्ट नहीं किया - आम तौर पर, सी ++ में, निर्माण और विनाश आदेश से संबंधित सबकुछ अच्छी तरह से निर्दिष्ट है। लेकिन कम से कम उन्होंने इसे निर्दिष्ट नहीं किया है, इसलिए कोई भी उस विशिष्ट संकलक का उपयोग करने के क्रम में भरोसा नहीं करेगा। –

3

मेरे पास सी ++ 11 दस्तावेज़ के अनुसार (यानी फ्रीबी, थोड़ा-पूर्व-अनुमोदन n3242), खंड 5.1.2, पैरा 21, कैप्चर घोषणा आदेश में बनाए गए हैं और रिवर्स घोषणा आदेश में नष्ट हो गए हैं । हालांकि, घोषणा आदेश निर्दिष्ट नहीं है (अनुच्छेद 14)। तो जवाब है, "अनिर्दिष्ट आदेश में" और "आप इसे प्रभावित नहीं कर सकते" (मुझे लगता है कि, एक कंपाइलर लिखकर)।

यदि बार को वास्तव में foo से पहले नष्ट करने की आवश्यकता है, तो बार के लिए एक साझा सूचक को पकड़ने के लिए बार के लिए बुद्धिमान होगा (या किसी प्रकार का)।

8

विनाश के आदेश पर चिंता करने की बजाय, आपको इस तथ्य को ठीक करना चाहिए कि यह एक समस्या है। यह नोट करते हुए कि आप दोनों ऑब्जेक्ट्स के लिए साझा पॉइंटर्स का उपयोग कर रहे हैं, आप ऑब्जेक्ट में एक साझा पॉइंटर जोड़कर विनाश के आदेश को सुनिश्चित कर सकते हैं जिसे आपको दूसरे को बाहर निकालने की आवश्यकता है। उस बिंदु पर foo या bar पहले नष्ट हो गया है इससे कोई फर्क नहीं पड़ता। यदि आदेश सही है, तो साझा सूचक का विनाश तुरंत वस्तुओं को छोड़ देगा। यदि ऑर्डर गलत है तो अतिरिक्त साझा पॉइंटर ऑब्जेक्ट को तब तक जीवित बनाए रखेगा जब तक कि दूसरा दूर नहीं जाता।

8

निकोल कहते हैं, विनाश का आदेश अनिर्दिष्ट है।

हालांकि, आपको लैम्ब्डा के विनाश पर निर्भर नहीं होना चाहिए। आप अपने लैम्ब्डा के अंत में foo को रीसेट करने में सक्षम होना चाहिए, इस प्रकार यह सुनिश्चित करना कि यह bar से पहले अपने संसाधन को जारी करता है। हालांकि आपको लैम्ब्डा को mutable के रूप में चिह्नित करना होगा। यहां एकमात्र नकारात्मकता यह है कि आप लैम्ब्डा को कई बार कॉल नहीं कर सकते हैं और इसे काम करने की उम्मीद करते हैं।

auto lambda = [foo, bar]() mutable { ...; foo.reset(); }; 

आप अपने लैम्ब्डा की जरूरत है, तो प्रतिदेय कई बार हो सकता है, तो आप आवंटन रद्द करने के आदेश को नियंत्रित करने के किसी अन्य तरीके के साथ आने की जरूरत है। एक विकल्प के रूप में इस तरह के एक std::pair<> एक ज्ञात डेटा सदस्य आदेश के साथ एक मध्यवर्ती संरचना का उपयोग करने, होगा:

auto p = std::make_pair(bar, foo); 
auto lambda = [p]() { auto foo = p.second, bar = p.first; ... }; 
+0

मेरे मामले में, लैम्ब्डा वास्तव में केवल एक बार निष्पादित होने की गारंटी है, इसलिए आपके मैन्युअल रीसेट दृष्टिकोण को ठीक काम करना चाहिए। मैं भूल गया कि एक साझा_पीटीआर अंक को जारी करने के लिए, आपको जरूरी रूप से इसे अक्षम करने की आवश्यकता नहीं है। आपका बहुत बहुत धन्यवाद! –

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

  • कोई संबंधित समस्या नहीं^_^