2013-06-12 8 views
7

क्या रिकर्सिव लैम्ब्डा फ़ंक्शन नियमित रिकर्सिव फ़ंक्शंस की तुलना में किसी भी ओवरहेड को प्रेरित करते हैं (क्योंकि हमें उन्हें std :: फ़ंक्शन में कैप्चर करना है)?
केवल इस कार्य के बीच क्या अंतर है और एक ही नियमित कार्य का उपयोग कर एक ही है?रिकर्सिव लैम्बडास के ओवरहेड

int main(int argc, const char *argv[]) 
{ 
    std::function<void (int)> helloworld = [&helloworld](int count) { 
     std::cout << "Hello world" << std::endl; 
     if (count > 1) helloworld(--count); 
    }; 
    helloworld(2); 
    return 0; 
} 
+2

आपकी मुख्य समस्या कम संकलक अनुकूलन होगी http://ideone.com/QsZVfH – stefan

+0

अच्छा! क्या आपको पता है क्यों? कंपाइलर यह अनुमान लगा सकता था कि यह कोड एक नियमित फ़ंक्शन कॉल के समान है (कोई कैप्चर नहीं है लेकिन खुद)? – 3XX0

+0

@fscan मुझे बाद में यह एक रिकर्सिव लैम्ब्डा फ़ंक्शन है। टाइप अनुमान – 3XX0

उत्तर

4

वहाँ भूमि के ऊपर एक std::function के रूप में यह भंडारण के द्वारा lambdas रिकर्सिवली उपयोग कर रहा है, हालांकि वे खुद को मूल रूप से functors हैं। ऐसा लगता है कि gcc अच्छी तरह अनुकूलित करने में सक्षम नहीं है जिसे सीधे comparison में देखा जा सकता है।

लैम्ब्डा के व्यवहार को कार्यान्वित करना, यानी एक मजेदार बनाने वाला, gcc को फिर से अनुकूलित करने में सक्षम बनाता है। एक लैम्ब्डा के अपने विशिष्ट उदाहरण के रूप में

struct HelloWorldFunctor 
{ 
    void operator()(int count) const 
    { 
     std::cout << "Hello world" << std::endl; 
     if (count > 1) 
     { 
     this->operator()(count - 1); 
     } 
    } 
}; 
int main() 
{ 
    HelloWorldFunctor functor; 
    functor(2); 
} 

उदाहरण मैं functor इस second demo में कैसा दिखेगा बनाए हैं उनके लिए लागू किया जा सकता।

यहां तक ​​कि अगर ऐसे ही एक std::rand के रूप में अशुद्ध कार्यों के लिए कॉल का परिचय है, एक पुनरावर्ती लैम्ब्डा के बिना या एक कस्टम functor साथ प्रदर्शन अभी भी बेहतर है। यहां एक third demo है।

निष्कर्ष: std::function के उपयोग के साथ, ओवरहेड है, हालांकि यह उपयोग के मामले के आधार पर नगण्य हो सकता है। चूंकि यह उपयोग कुछ कंपाइलर अनुकूलन को रोकता है, इसलिए इसका व्यापक रूप से उपयोग नहीं किया जाना चाहिए।

+0

यह सच है, कोड के लिए धन्यवाद, हालांकि मुझे संदेह है कि यह बहुत संकलक-विशिष्ट है। क्या विचारधारा पर कंपाइलर झंडे पास करने का कोई तरीका है? – Pedrom

+0

@ पेड्रोम मुझे ऐसा नहीं लगता। शायद अगर आप regis Ter? अस्वीकरण: मैंने अभी तक बड़े पैमाने पर लैम्ब्डा का उपयोग नहीं किया है क्योंकि जिन परियोजनाओं पर मैं काम करता हूं उन्हें लैम्बास का समर्थन नहीं करने वाले कंपाइलरों के साथ पिछड़ा संगतता की आवश्यकता होती है। – stefan

+0

मैं इसे अपनी मशीन पर मान्य करने की कोशिश कर रहा हूं, लेकिन किसी कारण से यह मुझे साइगविन का उपयोग करके कोई आउटपुट नहीं दिखाता है:/ – Pedrom

2

सी में lambdas ++ functors के बराबर हैं तो यह ही होगा कि संकलक द्वारा स्वचालित रूप से बनाया कुछ वर्ग के ऑपरेटर() कॉल। जब आप पर्यावरण को कैप्चर करते हैं तो दृश्यों के पीछे क्या हो रहा है यह है कि उन कब्जे वाले चर वर्ग के निर्माता को पास किए जाते हैं और सदस्य चर के रूप में संग्रहीत होते हैं।

तो संक्षेप में, प्रदर्शन अंतर शून्य के बहुत करीब होना चाहिए।

यहाँ वहाँ कुछ और स्पष्टीकरण है: "कर रहे हैं लैम्ब्डा क्लोजर लागू कैसे"

अनुभाग पर जाएं http://www.cprogramming.com/c++11/c++11-lambda-closures.html

संपादित करें:

कुछ अनुसंधान और स्टीफन जवाब और कोड के लिए धन्यवाद करने के बाद, यह पता चला std :: समारोह मुहावरा की वजह से पुनरावर्ती lambdas पर एक ओवरहेड नहीं है। चूंकि लैम्ब्डा को स्वयं को कॉल करने के लिए std :: फ़ंक्शन पर लपेटा जाना है, इसमें वर्चुअल फ़ंक्शन को कॉल करना शामिल है जो एक ओवरहेड जोड़ता है।

विषय इस जवाब की टिप्पणी पर इलाज किया जाता है: https://stackoverflow.com/a/14591727/1112142

+0

स्टीफन लववेज इसी तरह के विचार प्रस्तुत करते हैं [यहां] (http://channel9.msdn.com/Series/C9- व्याख्यान- स्टीफन- टी- लववेज- कोर- सी-/स्टीफन- टी- लववेज- कोर- सी-9- के-एन) (0:38:20 पर)। इस प्रकार ऐसा लगता है कि एक नियमित समारोह बुलाए जाने से कम ओवरहेड प्रेरित होगा। हालांकि मुझे कहीं पढ़ना याद है कि कुछ मामलों में इस मज़ेदार दृष्टिकोण को फ़ंक्शन पॉइंटर्स के साथ अनुकूलित किया जा सकता है। क्या यह सच है ? मेरे द्वारा प्रदान किए गए मामले के बारे में क्या? – 3XX0

+0

@ 3XX0 यह एक अच्छा वीडियो है, लिंक के लिए धन्यवाद :) हालांकि उन्होंने कहा कि यदि आप इसे और अधिक इस्तेमाल करने की योजना बनाते हैं तो नियमित कार्य लिखने का अर्थ होगा, लेकिन ऐसा इसलिए है क्योंकि विभिन्न हिस्सों में कॉल करना आसान है कोड, वह प्रदर्शन के बारे में बात नहीं कर रहा है। फ़ंक्शन पॉइंटर्स चीज़ के बारे में, आप * लैंबडास के बजाय * उनका उपयोग कर सकते हैं, लेकिन मुझे नहीं लगता कि वे सुविधाजनक होने जा रहे हैं और अभ्यास में मैंने कोई प्रदर्शन अंतर नहीं देखा है। – Pedrom

+0

@ 3XX0 आपके उदाहरण के लिए, यह एक फ़ंक्शन शून्य हैलो_वर्ल्ड (myfunc foo, int count) को कॉल करने जैसा है, यदि कोई * ओवरहेड है तो यह पहले कॉल पर होगा (क्योंकि आपको इसे ऑब्जेक्ट फू को तुरंत पास करने की आवश्यकता है विधि के लिए, लेकिन उसके बाद निम्नलिखित सभी कॉल प्रदर्शन के संदर्भ में बिल्कुल समान हैं। इसके अलावा, यदि आपका रिकर्सिव फ़ंक्शन एक विधि है तो इसमें कोई अंतर नहीं है। – Pedrom

3

तो std::function polymorphically लागू किया गया है। अपने कोड अर्थ मोटे तौर पर के बराबर है:

struct B 
{ 
    virtual void do(int count) = 0; 
}; 

struct D 
{ 
    B* b; 
    virtual void do(int count) 
    { 
     if (count > 1) 
      b->do(count--); 
    } 
}; 

int main() 
{ 
    D d; 
    d.b = &d; 
    d.do(10); 
} 

यह एक तंग पर्याप्त प्रत्यावर्तन ऐसी है कि एक आभासी विधि देखने एक महत्वपूर्ण ओवरहेड है के लिए दुर्लभ है, लेकिन अपने आवेदन क्षेत्र के आधार पर यह निश्चित रूप से संभव है।

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