2013-05-26 7 views
6

क्यों कब्जा कर लिया-दर-मूल्य रहे हैं मान स्थिरांक, लेकिन कब्जा कर लिया-दर-संदर्भ वस्तुओं नहीं:लैम्ब्डा: कैप्चर-बाय-वैल्यू वैल्यू क्यों हैं, लेकिन कैप्चर-बाय-रेफरेंस मान नहीं हैं?

int a; 

auto compile_error = [=]() 
{ 
    a = 1; 
} 
auto compiles_ok = [&]() 
{ 
    a = 1; 
} 
मेरे लिए

इस विसंगत लग रहे है, लेकिन यह मानक होने लगते हैं? विशेष रूप से एक कब्जे वाले मूल्य के अवांछित संशोधन एक कष्टप्रद बग हो सकता है, लेकिन संभावना अधिक है कि परिणाम लैम्ब्डा गुंजाइश तक ही सीमित हैं, जबकि संदर्भ द्वारा प्राप्त वस्तुओं की अवांछित संशोधन अक्सर अधिक गंभीर प्रभाव पैदा करेगा।

तो प्रति डिफ़ॉल्ट कॉन्स्ट संदर्भ द्वारा कैप्चर क्यों नहीं करें? या कम से कम समर्थन [const &] और [&]? इस डिजाइन के कारण क्या हैं?

वर्कअराउंड के रूप में आपको शायद मूल्य से कब्जा कर लिया गया std :: cref wrapped const संदर्भों का उपयोग करना चाहिए?

+0

संदर्भ को कैप्चर करने में अधिकांश बिंदु इसे बदल रहा है। मूल्य बदलने के लिए * नहीं * कारण है - यह व्यर्थ है। – Elazar

+3

संदर्भ अपरिवर्तनीय हैं और बाध्य होने के बाद कभी नहीं बदला जा सकता है। तो एक अर्थ में लैम्ब्डा अभिव्यक्तियां बाकी की भाषा के साथ संगत हैं। आप लैम्ब्डा अभिव्यक्तियों के लिए 'म्यूटेबल' का अर्थ जानना चाहेंगे। –

+0

@ एलाजार: अस्थायी के रूप में मूल्य बदला जा सकता है, लेकिन फिर भी जब आप सुझाव देते हैं कि मूल्य बदलने के लिए कोई समस्या नहीं है, जबकि एक संदर्भित वस्तु को बदलना वास्तव में अन्य क्षेत्रों को प्रभावित करता है जो अनजान (बग) हो सकते हैं। – valoh

उत्तर

1

कैप्चर किए गए संदर्भ भी const हैं। या इसके बजाय, संदर्भ हमेशा निहित const - भाषा में कोई वाक्यविन्यास नहीं है जो आपको संदर्भ बिंदुओं को बदलने की अनुमति देता है। a = 1; जब a एक संदर्भ संदर्भ को बदल नहीं रहा है, लेकिन संदर्भ संदर्भों को बदल रहा है।

जब आप "कॉन्स्ट रेफरेंस" के बारे में बात करते हैं, तो मुझे लगता है कि आप उलझन में हैं। आप "कॉन्स्ट int के संदर्भ" (const int &) के बारे में बात कर रहे हैं। "कॉन्स्ट" संदर्भ संदर्भ बिंदु को संदर्भित करता है, संदर्भ स्वयं नहीं। यह पॉइंटर्स के समान है: "पॉइंटर टू कॉन्स्ट इंट" (const int *) के साथ, पॉइंटर स्वयं const नहीं है - आप इस प्रकार के वैरिएबल को असाइन कर सकते हैं जो आप चाहते हैं। एक असली "कॉन्स पॉइंटर" int *const होगा। यहां, आप इस प्रकार के कुछ को असाइन नहीं कर सकते हैं; लेकिन आप int को इंगित कर सकते हैं। इसलिए, पॉइंटर या संदर्भ के लिए "कॉन्स्ट" उस चीज़ के लिए "कॉन्स्ट" से अलग है जो यह इंगित करता है। आपके पास "कॉन्स्ट int के लिए कॉन्स्ट पॉइंटर" भी हो सकता है: const int *const

+1

बेशक मुझे पता है कि संदर्भ हमेशा एक ही वस्तु के संदर्भ में हमेशा संदर्भित होते हैं, जिसका मेरा मतलब था कॉन्स्ट वैल्यू (निश्चित भ्रामक विषय) के संदर्भ में संदर्भ। मल्टीथ्रेडिंग (टास्क स्टीलिंग सिस्टम) के संदर्भ में लैम्बडास का उपयोग करते समय, अनपेक्षित लिखने से आसानी से दौड़ की स्थिति बढ़ जाती है। कॉन्स शुद्धता सी ++ की अवधारणा के साथ इमो अन्य भाषाओं (जैसे सी #) पर एक लाभ है, लेकिन लैम्बडास के संदर्भ में यह थोड़ा गन्दा लग रहा है। और मैं इस कारण को जानना चाहूंगा कि कॉन्स्ट लैम्बडास रखने का कोई आसान तरीका क्यों नहीं है जहां बदली गई वस्तुओं को स्पष्ट रूप से चिह्नित किया गया है। – valoh

0

मेरा तर्क निम्नानुसार है: लैम्बडा वैकल्पिक आवश्यक संदर्भों के साथ कोड का एक टुकड़ा है। इस मामले में जब आपको वास्तव में कुछ कॉपी करने की आवश्यकता होती है (जो आमतौर पर स्मृति प्रबंधन उद्देश्यों के लिए होता है, जैसे कि shared_ptr की प्रतिलिपि बनाना), आप अभी भी वास्तव में लैम्बडा को अपना राज्य नहीं चाहते हैं। यह काफी असामान्य स्थिति है।

मुझे लगता है कि केवल 2 निम्नलिखित विकल्पों के "सही"

  • कुछ स्थानीय चर का उपयोग कर कुछ कोड संलग्न करें, ताकि आप "इसके चारों ओर से पारित" कर सकते हैं
  • ऊपर तरह ही, लेकिन स्मृति प्रबंधन जोड़ने लग रहा है , क्योंकि हो सकता है कि आप कोड के उस टुकड़े को असीमित रूप से या कुछ निष्पादित करना चाहते हैं, और निर्माण का दायरा गायब हो जाएगा।

लेकिन जब एक लैम्ब्डा "परिवर्तनशील" है, यानी, वह मान जो const नहीं कर रहे हैं कैप्चर करता है, इसका मतलब है कि यह वास्तव में अपने स्वयं के राज्य का समर्थन करता है। मतलब, हर बार जब आप लैम्ब्डा पर कॉल करते हैं, तो यह एक अलग परिणाम उत्पन्न कर सकता है, जो इसके वास्तविक बंद पर आधारित नहीं है, लेकिन फिर से, इसके आंतरिक राज्य पर, जो मेरी पुस्तक में प्रति-अंतर्ज्ञानी है , यह मानते हुए कि लैम्ब्डा कार्यात्मक भाषाओं में उत्पन्न होता है।

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

मुझे आपके साथ इस कारण की उम्मीद है।

+0

मैं पूरी तरह से समझता हूं कि कैप्चर-बाय-वैल्यू क्यों हैं और पूरी तरह से सहमत हैं कि डिफ़ॉल्ट रूप से इसे रखना एक अच्छा विचार है। लेकिन जो भी मुझे अभी भी नहीं मिलता है वह कैप्चर-बाय-रेफरेंस के लिए गायब स्थिरता समर्थन है, विशेष रूप से यह बहु थ्रेडेड वातावरण में मजबूत लैम्बा उपयोग को रोकता है -> गैर-कॉन्स == संभावित दौड़ की स्थिति इतनी बेहतर है कि केवल गैर- जब आप वास्तव में इसका मतलब है। – valoh

+0

ओह। मैं कहूंगा कि यह कुछ बढ़िया मामला है। एक लैम्ब्डा आईएमओ स्थानीय चर के साथ सौदों के रूप में वे हैं। यदि आपने प्रत्येक किनारे के मामले के लिए विशेष वाक्यविन्यास जोड़ा है, तो आप कम से कम एक राक्षसी नींद के साथ समाप्त हो जाएंगे ... अच्छी तरह से, एक * अधिक * राक्षसी, कम से कम।जैसा कि आप कल्पना कर सकते हैं, अभी भी यह संभव है कि आप जो चाहते हैं उसे प्राप्त करें, बस अपने चर को अपने कॉन्फ़िगर करने के लिए, और उसके बाद उस उपनाम को कैप्चर करके। –

+0

शायद मैं बहुत अधिक उम्मीद कर रहा हूं :-) और वास्तव में मुझे लगता है कि मैंने अपने मूल प्रश्न को बहुत गलत समझा। अब मैं कैप्चर-बाय-वैल्यू को कैप्चर-बाय-रेफरेंस पर लागू करने के लिए उसी कारण पर बहस करता हूं। और एक कॉन्स ऑब्जेक्ट को संशोधित करने के लिए आपके पास हमेशा कास्ट कास्ट होता है जो इसे वास्तव में स्पष्ट करता है कि क्या संशोधित होता है। [Const &]() {} के लिए कम से कम समर्थन बहुत ज्यादा नहीं लगता है। वर्तमान रूप में कैप्चर-बाय-रेफरेंस का कॉन्स्ट हैंडलिंग थोड़ा सा मैला लगता है और यह एक साफ और मजबूत उपयोग का समर्थन नहीं करता है। – valoh

7

मान लें कि आप मूल्य के आधार पर सूचक को कैप्चर कर रहे हैं। पॉइंटर स्वयं ही होता है, लेकिन उस ऑब्जेक्ट तक पहुंच जो इंगित करता है वह नहीं है।

int* const p; 

इसी बात के लिए एक संदर्भ के साथ होता है:

struct lambda { 
    int* p; 
    lambda(int* p_) : p(p_) {} 
    void operator()() const { ++*p; } 
}; 

constoperator()() पर के रूप में यह घोषित करने के लिए p बराबर का उपयोग करता है:

int i = 0; 
int* p = &i; 
auto l = [=]{ ++*p; }; 
l(); 
std::cout << i << std::endl; // outputs 1 

यह लैम्ब्डा के बराबर है। संदर्भ स्वयं "कॉन्स्ट" है (उद्धरणों में क्योंकि संदर्भों को संशोधित नहीं किया जा सकता है), लेकिन उस ऑब्जेक्ट तक पहुंच जो इसका संदर्भ है वह नहीं है।

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