प्रश्न में लंबोदर का वास्तव में कोई राज्य नहीं है ।
की जांच:
struct lambda {
auto operator()() const { return 17; }
};
और अगर हमारे पास था lambda f;
, तो यह एक खाली वर्ग है। न केवल उपर्युक्त lambda
कार्यात्मक रूप से आपके लैम्ब्डा के समान है, यह है (मूल रूप से) कि आपका लैम्ब्डा कैसे लागू किया जाता है! (इसे सूचक संचालक को कार्य करने के लिए एक अंतर्निहित कलाकार की आवश्यकता होती है, और नाम lambda
को कुछ संकलक-जनित छद्म मार्गदर्शक के साथ प्रतिस्थापित किया जा रहा है)
C ++ में, ऑब्जेक्ट पॉइंटर्स नहीं हैं। वे वास्तविक चीजें हैं। वे केवल उन डेटा को संग्रहीत करने के लिए आवश्यक स्थान का उपयोग करते हैं। किसी वस्तु का सूचक किसी वस्तु से बड़ा हो सकता है।
जब आप एक समारोह के लिए एक संकेत के रूप में उस मेमने के बारे में सोच सकते हैं, यह नहीं है। आप auto f = [](){ return 17; };
एक अलग फ़ंक्शन या लैम्ब्डा को पुन: असाइन नहीं कर सकते हैं !
auto f = [](){ return 17; };
f = [](){ return -42; };
उपरोक्त अवैध है । में कोई जगह नहीं है f
की दुकान में जो समारोह के नाम से जाना जा रहा है - कि जानकारी में संग्रहित है प्रकार की f
, के मूल्य में नहीं f
!
यदि आपने ऐसा किया है:
int(*f)() = [](){ return 17; };
या यह:
std::function<int()> f = [](){ return 17; };
अब आप सीधे मेमने का भंडारण नहीं कर रहे हैं। इन दोनों मामलों में, f = [](){ return -42; }
कानूनी है - इसलिए इन मामलों में, हम यह मान रहे हैं कि हम किस फ़ंक्शन को मान रहे हैं f
। और sizeof(f)
अब नहीं है 1
, लेकिन बल्कि sizeof(int(*)())
या बड़ा (मूल रूप से, सूचक आकार या बड़ा हो, जैसा कि आप उम्मीद करते हैं। std::function
मानक द्वारा निहित एक न्यूनतम आकार है (उन्हें एक निश्चित आकार तक "खुद के अंदर कॉलबेल" स्टोर करने में सक्षम होना चाहिए) कम से कम उतने बड़े हैं जितने कि फंक्शन पॉइंटर प्रैक्टिस में)।
में int(*f)()
मामला है, आप एक समारोह के लिए एक समारोह सूचक भंडारण कर रहे हैं कि बर्ताव करता है के रूप में यदि आप उस लैम्ब्डा कहा जाता है। यह केवल स्टेटलेस लैम्ब्डा (खाली []
कैप्चर लिस्ट वाले लोगों ) के लिए काम करता है ।
में std::function<int()> f
मामला है, आप एक प्रकार-विलोपन वर्ग पैदा कर रहे std::function<int()>
उदाहरण है कि (इस मामले में) में प्लेसमेंट के लिए एक आंतरिक बफर में आकार -1 लैम्ब्डा की एक प्रति स्टोर करने के लिए नए (और उपयोग करता है, एक बड़ा लैम्ब्डा में पारित किया गया था, तो (अधिक राज्य के साथ ), ढेर आवंटन का उपयोग करेगा)।
एक अनुमान के रूप में, ऐसा कुछ है जो आप सोचते हैं कि शायद चल रहा है। वह लंबोदर एक वस्तु है जिसका प्रकार उसके हस्ताक्षर द्वारा वर्णित है। सी ++ में, मैनुअल फ़ंक्शन ऑब्जेक्ट कार्यान्वयन पर लंबोदा शून्य लागत सार बनाने का निर्णय लिया गया था । यह आपको एक लैंबडा को एक std
एल्गोरिथ्म (या समान) में पास करने देता है और इसकी सामग्री कंपाइलर को पूरी तरह से दिखाई दे सकती है जब यह एल्गोरिथम टेम्पलेट को तत्काल तैयार करता है। यदि एक लंबोदर के पास एक प्रकार था std::function<void(int)>
, तो इसकी सामग्री पूरी तरह से दिखाई नहीं देगी, और एक हाथ से तैयार की गई फ़ंक्शन ऑब्जेक्ट तेज हो सकती है।
सी ++ मानकीकरण का लक्ष्य हाथ से तैयार किए गए सी कोड पर शून्य ओवरहेड के साथ उच्च स्तरीय प्रोग्रामिंग है।
अब जब आप समझते हैं कि आपका f
वास्तव में स्टेटलेस है, तो आपके सिर में एक और सवाल होना चाहिए: लैम्ब्डा की कोई स्थिति नहीं है। इसका आकार क्यों नहीं है 0
?
संक्षिप्त उत्तर है।
C ++ की सभी वस्तुओं का मानक के तहत 1 का न्यूनतम आकार होना चाहिए, और एक ही प्रकार की दो वस्तुओं का समान पता नहीं हो सकता है। ये जुड़े हुए हैं, क्योंकि एक प्रकार के सरणी में T
तत्वों sizeof(T)
को अलग रखा जाएगा ।
अब, क्योंकि इसमें कोई राज्य नहीं है, कभी-कभी यह कोई स्थान नहीं ले सकता है। यह तब नहीं हो सकता जब यह "अकेला" हो, लेकिन कुछ संदर्भों में यह हो सकता है। std::tuple
और इसी तरह के पुस्तकालय कोड इस तथ्य का फायदा उठाते हैं। यहाँ दिया गया है कि यह कैसे काम करता है:
के रूप में एक लैम्ब्डा एक वर्ग के बराबर है जिसमें operator()
अतिभारित, स्टेटलेस लैम्ब्डा (एक []
कैप्चर सूची के साथ) सभी खाली वर्ग हैं। वे sizeof
की 1
। वास्तव में, यदि आप उनसे विरासत में प्राप्त हुए हैं (जो अनुमति दी गई है!), वे तब तक कोई स्थान नहीं लेंगे, जब तक कि वह एक ही प्रकार के पते की टक्कर का कारण न बने । (इसे खाली आधार अनुकूलन के रूप में जाना जाता है)।
template<class T>
struct toy:T {
toy(toy const&)=default;
toy(toy &&)=default;
toy(T const&t):T(t) {}
toy(T &&t):T(std::move(t)) {}
int state = 0;
};
template<class Lambda>
toy<Lambda> make_toy( Lambda const& l ) { return {l}; }
sizeof(make_toy( []{std::cout << "hello world!\n"; } ))
है sizeof(int)
(अच्छी तरह से, ऊपर अवैध है, क्योंकि आप एक गैर का मूल्यांकन संदर्भ में एक लैम्ब्डा नहीं बना सकते: यदि आप एक नामित बनाने के लिए auto toy = make_toy(blah);
तो sizeof(blah)
है, लेकिन वह सिर्फ शोर है)। sizeof([]{std::cout << "hello world!\n"; })
अभी भी 1
(समान योग्यता) है।
यदि हम एक और खिलौना प्रकार बनाते हैं:
template<class T>
struct toy2:T {
toy2(toy2 const&)=default;
toy2(T const&t):T(t), t2(t) {}
T t2;
};
template<class Lambda>
toy2<Lambda> make_toy2( Lambda const& l ) { return {l}; }
यह मेमने की दो प्रतियां हैं । के रूप में वे एक ही पता साझा नहीं कर सकते, sizeof(toy2(some_lambda))
है 2
!
struct
साथ लागू किया गयाoperator()