2012-12-11 23 views
24

मुख्य सवाल से एक स्थिर चर कैप्चरिंग

मैं जीसीसी 4.7.2 के साथ निम्न कोड को संकलित करने के कोशिश कर रहा हूँ:एक सी ++ 11 लैम्ब्डा में संदर्भ

#include <iostream> 

int foo() { 
    static int bar; 
    return [&bar]() { return bar++; }(); // lambda capturing by reference 
} 

int main (int argc, char* argv[]) { 
    std::cout << foo() << std::endl; 
    return 0; 
} 

और ऐसा लगता है कि नहीं है अच्छी तरह से जा रहा है, उत्पादन के रूप में इस एक है:

$p2.cpp: In function ‘int foo()’: 
$p2.cpp:6:14: warning: capture of variable ‘bar’ with non-automatic storage duration [enabled by default] 
$p2.cpp:4:16: note: ‘int bar’ declared here 

तो, मेरा पहला सवाल होगा:

क्या यह जीसीसी की विफलता है, या कोड वैध सी ++ 11 नहीं है? क्या यह जीसीसी के किसी भी हालिया संस्करण में तय है?

एक shared_ptr कारखाने

मैं इस सिद्धांत पर आधारित एक विरूपण साक्ष्य का निर्माण करने पर विचार में चाल का उपयोग करते हुए, लेकिन एक गैर शाब्दिक स्थिर चर का उपयोग कर। यह आर्टिफैक्ट साझा_ptr < टी> ऑब्जेक्ट्स का एक कारखाना है, जो कि नई टी ऑब्जेक्ट्स के निर्माण से बचते हैं जब आपको एक ही उदाहरण के लिए डुप्लिकेट shared_ptr कंटेनर की आवश्यकता होती है।

यह विरूपण साक्ष्य लगेगा जैसे:

std::shared_ptr<Foo> create(std::string name) { 
    static std::unordered_map<std::string,std::weak_ptr<Foo>> registry; 

    if (auto it = registry.find(name) != registry.end()) 
     return registry[name].lock(); 

    auto b = std::shared_ptr<Foo>(
     new Foo(name), 
     [&registry] (Foo* p) { 
      registry.erase(p->getName()); 
      delete p; 
     }); 

    registry.emplace(name,b); 
    return b; 
} 

जहाँ तक मुझे पता है, अगर जीसीसी मुद्दे से पहले चर्चा की सी ++ 11 अनुरूपता के मामले में एक समस्या नहीं है, इस विरूपण साक्ष्य नहीं एक मुद्दा होना चाहिए या तो। इस हैक का उपयोग करके देखभाल करने वाली एकमात्र चीज, परिणामस्वरूप shared_ptr < टी> ऑब्जेक्ट को किसी भी वैश्विक ऑब्जेक्ट पर सेट नहीं करना है जिसे स्थैतिक चर के बाद नष्ट किया जा सकता है।

क्या मैं इस बारे में सही हूं?

+0

जी ++ पर संकलित और चलाता है 4.6.3 – goji

उत्तर

58

आप bar पर कब्जा करने की कोशिश क्यों कर रहे हैं? यह स्थिर है। आपको इसे बिल्कुल कैप्चर करने की आवश्यकता नहीं है। केवल स्वचालित चर को कैप्चरिंग की आवश्यकता होती है। Clang केवल एक चेतावनी नहीं, आपके कोड पर एक कठिन त्रुटि फेंकता है। और यदि आप अपने लैम्ब्डा कैप्चर से &bar हटाते हैं, तो कोड पूरी तरह से काम करता है।

#include <iostream> 

int foo() { 
    static int bar; 
    return []() { return bar++; }(); // lambda capturing by reference 
} 

int main (int argc, char* argv[]) { 
    std::cout << foo() << std::endl; 
    std::cout << foo() << std::endl; 
    std::cout << foo() << std::endl; 
    return 0; 
} 

प्रिंट

0 
1 
2 
+0

असम्बद्ध कोड g ++ 4.6.3 पर ठीक काम करता है ?? – goji

+1

@ ट्रॉय: शायद जी ++ 4.6.3 में एक बग। –

+0

मीठे, सोचा कि यह इस परिस्थिति में दायरे में नहीं था, धन्यवाद। –

11

मानक के अनुसार, आप केवल स्वत: भंडारण अवधि (या this है, जो के रूप में स्पष्ट रूप से उल्लेख किया गया है capturable) के साथ चर पर कब्जा कर सकते हैं।

तो, नहीं, तुम ऐसा नहीं कर सकते मानक के अनुसार (या, अपने पहले सवाल का जवाब देने, जो मान्य सी ++ 11 नहीं है और एक संकलक बग नहीं है)

5.1.1/2 लैम्ब्डा-कैप्चर में एक नाम लैम्ब्डा अभिव्यक्ति के संदर्भ में गुंजाइश में होगा, और यह स्थानीय संग्रहण परिवर्तनीय या स्वचालित संग्रहण अवधि के संदर्भ में होगा।

संपादित करें: और, जैसा कि केविन ने उल्लेख किया है, आपको किसी भी स्थानीय static पर कब्जा करने की आवश्यकता नहीं है।

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