दिलचस्प पोस्ट
क्या मुझे बगल में रखने वाला कोई भी एएसपी.नेट एमवीसी नहीं मिलता है? कैसे सीरियल पोर्ट से पढ़ें और लिखें Google मानचित्र कैसे शहर या एक क्षेत्र की रूपरेखा दिखाना है PHP में एकाधिक फ़ाइल अपलोड करें जावा में स्पष्ट प्रकार की कास्टिंग उदाहरण बाइट सरणी के लिए जावा पूर्णांक IE9 के लिए फ्लेक्सबॉक्स विकल्प पुनरावर्ती पदानुक्रम – LINQ का उपयोग करके रिकर्सिव क्वेरी मेरे आवेदन और एक्सेस क्वेरी विज़ार्ड के बीच भिन्न तरह के व्यवहार 1/1/1970 "युग का समय" क्यों है? एरे बनाम वेक्टर: परिचयात्मक समानताएं और अंतर jQuery UI टैब वर्तमान में चयनित टैब सूचकांक प्राप्त करें कोको में XML को पार्स करना Coredata त्रुटि "डेटा: <fault>" जावा उपलब्ध स्मृति उपलब्ध है

क्या मुझे std :: function या C ++ में फ़ंक्शन पॉइंटर का उपयोग करना चाहिए?

C ++ में कॉलबैक फ़ंक्शन को कार्यान्वित करते समय, अब भी मैं C-style फ़ंक्शन पॉइंटर का उपयोग करना चाहिए:

void (*callbackFunc)(int); 

या मुझे std :: function का उपयोग करना चाहिए:

 std::function< void(int) > callbackFunc; 

वेब के समाधान से एकत्रित समाधान "क्या मुझे std :: function या C ++ में फ़ंक्शन पॉइंटर का उपयोग करना चाहिए?"

संक्षेप में, std::function उपयोग करें जब तक आपके पास ऐसा करने का कोई कारण नहीं है।

फंक्शन पॉइन्टर्स को कुछ संदर्भों पर कब्जा करने में सक्षम नहीं होने का नुकसान होता है आप उदाहरण के लिए कॉलबैक के रूप में एक लैम्ब्डा फ़ंक्शन को पास नहीं कर पाएंगे, जो कुछ संदर्भ चर को लेता है (लेकिन अगर यह किसी भी कब्जा नहीं करता है तो यह काम करेगा)। ऑब्जेक्ट के सदस्य चर को कॉल करना (अर्थात गैर-स्थिर) इस प्रकार भी संभव नहीं है, क्योंकि ऑब्जेक्ट ( this पॉइंटर) को कब्जा कर लिया जाना चाहिए। (1)

std::function (जब से C ++ 11) प्राथमिक रूप से किसी फ़ंक्शन को संग्रहीत करने के लिए है (इसे पास करने के लिए इसे संग्रहीत करने की आवश्यकता नहीं है)। इसलिए यदि आप एक सदस्य चर में उदाहरण के लिए कॉलबैक को संग्रहीत करना चाहते हैं, तो यह शायद आपका सबसे अच्छा विकल्प है लेकिन अगर आप इसे संग्रहीत न करते हैं, तो यह एक अच्छी "पहली पसंद" है, हालांकि इसे कुछ (बहुत छोटे) ओवरहेड को शुरू करने का नुकसान होता है (बुलाया जा रहा है, इसलिए बहुत ही प्रदर्शन-गंभीर स्थिति में यह एक समस्या हो सकती है, लेकिन अधिकतर यह नहीं होना चाहिए)। यह बहुत "सार्वभौमिक" है: यदि आप लगातार और पठनीय कोड के बारे में बहुत ध्यान रखते हैं और साथ ही आप जो भी पसंद करते हैं (यानी इसे सरल रखना चाहते हैं) के बारे में सोचना नहीं चाहते हैं, तो आप पास हर फ़ंक्शन के लिए std::function उपयोग करें चारों ओर।

एक तिहाई विकल्प के बारे में सोचें: यदि आप एक छोटे फ़ंक्शन को कार्यान्वित करने वाले हैं जो फिर प्रदान की गई कॉलबैक फ़ंक्शन के माध्यम से कुछ रिपोर्ट करता है, तो एक टेम्प्लेट पैरामीटर पर विचार करें, जो फिर कोई कॉल करने योग्य ऑब्जेक्ट हो सकता है, जो कि फ़ंक्शन पॉइंटर, मजेदार चिकित्सक, लैम्ब्डा, एक std::function , … यहां ड्राफ्ट यह है कि आपका (बाह्य) फ़ंक्शन एक टेम्प्लेट हो जाता है और इसलिए हेडर में कार्यान्वित करने की आवश्यकता है दूसरी ओर आपको फायदा मिलता है कि कॉलबैक को कॉल को इनलाइन किया जा सकता है, क्योंकि ग्राहक (बाहरी) फ़ंक्शन कॉलबैक को कॉल "देखता है" सटीक प्रकार की जानकारी उपलब्ध होगी।

टेम्पलेट पैरामीटर के साथ संस्करण के लिए उदाहरण (pre-C ++ 11 के लिए & इसके बजाय & लिखने):

 template <typename CallbackFunction> void myFunction(..., CallbackFunction && callback) { ... callback(...); ... } 

जैसा कि आप निम्न तालिका में देख सकते हैं, उनमें से सभी के पास उनके फायदे और नुकसान हैं:

 +-------------------+--------------+---------------+----------------+ | | function ptr | std::function | template param | +===================+==============+===============+================+ | can capture | no(1) | yes | yes | | context variables | | | | +-------------------+--------------+---------------+----------------+ | no call overhead | yes | no | yes | | (see comments) | | | | +-------------------+--------------+---------------+----------------+ | can be inlined | no | no | yes | | (see comments) | | | | +-------------------+--------------+---------------+----------------+ | can be stored | yes | yes | no(2) | | in class member | | | | +-------------------+--------------+---------------+----------------+ | can be implemented| yes | yes | no | | outside of header | | | | +-------------------+--------------+---------------+----------------+ | supported without | yes | no(3) | yes | | C++11 standard | | | | +-------------------+--------------+---------------+----------------+ | nicely readable | no | yes | (yes) | | (my opinion) | (ugly type) | | | +-------------------+--------------+---------------+----------------+ 

(1) इस सीमा को पार करने के लिए myFunction(..., callback, data) मौजूद हैं, उदाहरण के लिए अतिरिक्त (बाहरी) फ़ंक्शन के अतिरिक्त पैरामीटर के रूप में अतिरिक्त डेटा देना: myFunction(..., callback, data) callback(data) कॉल करेंगे यह सी-शैली "तर्कों के साथ कॉलबैक" है, जो सी ++ में संभव है (और जिस तरह से व्यापक रूप से WIN32 API में प्रयुक्त होता है), लेकिन इसे टाला जाना चाहिए क्योंकि हमारे पास सी ++ में बेहतर विकल्प हैं

(2) जब तक हम क्लास टेम्प्लेट के बारे में बात नहीं कर रहे हैं, यानी जिस वर्ग में आप फ़ंक्शन को स्टोर करते हैं वह एक टेम्पलेट है। लेकिन इसका मतलब यह होगा कि ग्राहक पक्ष पर फ़ंक्शन का प्रकार ऑब्जेक्ट के प्रकार का फैसला करता है जो कॉलबैक को संग्रहीत करता है, जो लगभग वास्तविक उपयोग मामलों के लिए कोई विकल्प नहीं है।

(3) प्री-सी ++ 11 के लिए, boost::function उपयोग करें

void (*callbackFunc)(int); एक सी शैली कॉलबैक फ़ंक्शन हो सकती है, लेकिन यह खराब डिज़ाइन का एक बेहद बेकार है।

एक अच्छी तरह से डिज़ाइन सी स्टाइल कॉलबैक void (*callbackFunc)(void*, int); की तरह दिखता है void (*callbackFunc)(void*, int); – इसमें कोड को अनुमति देने के लिए void* जो कॉलबैक को कार्य से परे स्थिति बनाए रखने के लिए करता है। ऐसा नहीं करने से कॉलर को वैश्विक स्तर पर स्टोर करने के लिए मजबूर किया जाता है, जो अमूल्य है

std::function< int(int) > अधिक कार्यान्वयन में int(*)(void*, int) तुलना में थोड़ा ज्यादा महंगा हो जाता है। हालांकि कुछ कंपाइलरों को इनलाइन के लिए कठिन है। स्टडी std::function क्लोन कार्यान्वयन हैं जो प्रतिद्वंद्वी फ़ंक्शन पॉइंटर इनवॉकेशन ओवरहेड्स ('सबसे तेजी से संभव प्रतिनिधि' आदि देखें) जो कि पुस्तकालयों में अपना रास्ता बना सकते हैं।

अब, एक कॉलबैक सिस्टम के ग्राहकों को अक्सर संसाधनों को सेट अप करने और कॉलबैक बनाए और हटाए जाने पर और कॉलबैक के जीवनकाल के बारे में जागरूक होने की आवश्यकता होती है। void(*callback)(void*, int) यह प्रदान नहीं करता है

कभी-कभी यह कोड संरचना (कॉलबैक के सीमित जीवनकाल में) या अन्य तंत्र के माध्यम से उपलब्ध होता है (कॉलबैक और जैसी तरह से अनर्जेंट)।

std::function सीमित जीवनकाल प्रबंधन के लिए एक साधन प्रदान करता है (ऑब्जेक्ट की अंतिम प्रतिलिपि यह भूल जाती है जब दूर जाता है)।

आम तौर पर, जब तक प्रदर्शन चिंता प्रकट नहीं होता तब तक मैं std::function उपयोग करता हूं यदि वे करते हैं, तो मैं पहले संरचनात्मक परिवर्तन (एक प्रति-पिक्सेल कॉलबैक के बजाय, जो मुझे लम्बाडा के आधार पर स्कैनलाइन प्रोसेसर के निर्माण के बारे में बताता था) को पारित करने के लिए होता था? फंक्शन-कॉल ओवरहेड को तुच्छ स्तरों को कम करने के लिए पर्याप्त होना चाहिए )। फिर, अगर यह बनी रहती है, तो मैं एक delegate को सबसे तेज़ संभावित प्रतिनिधियों के आधार पर लिखना चाहता हूं, और देखें कि क्या प्रदर्शन समस्या दूर हो जाती है।

मैं प्रायः विरासत एपीआई के लिए फ़ंक्शन पॉइंटर्स का उपयोग करता हूं, या अलग-अलग कंपाइलर जनरेटेड कोड के बीच संचार के लिए सी इंटरफेस बनाने के लिए। मैंने उन्हें आंतरिक क्रियान्वयन विवरण के रूप में भी उपयोग किया है जब मैं कूद तालिकाओं, प्रकार के विलोपन, आदि को लागू कर रहा हूं: जब मैं दोनों उत्पादन और उपभोग करता हूं, और किसी भी ग्राहक कोड का उपयोग करने के लिए इसे बाहरी रूप से उजागर नहीं कर रहा हूं, और फ़ंक्शन पॉइंटर्स मुझे ज़रूर करते हैं ।

ध्यान दें कि आप wrappers लिख सकते हैं जो std::function<int(int)> एक int(void*,int) शैली कॉलबैक में बदलते हैं, यह मानते हुए कि उचित कॉलबैक लाइफटाइम प्रबंधन इंफ्रास्ट्रक्चर हैं। इसलिए किसी भी सी-स्टाइल कॉलबैक लाइफटाइम प्रबंधन सिस्टम के लिए एक धुआं परीक्षण के रूप में, मुझे यह सुनिश्चित करना होगा कि std::function लपेट करना काफी अच्छी तरह से काम करता है

मनमाना करने योग्य वस्तुओं को संग्रहित करने के लिए std::function का उपयोग करें यह उपयोगकर्ता को कॉलबैक के लिए आवश्यक संदर्भ प्रदान करने की अनुमति देता है; एक सादा समारोह सूचक नहीं करता है

अगर आपको किसी कारण (शायद आप एक सी-संगत एपीआई चाहते हैं) के लिए सादा फ़ंक्शन पॉइंटर्स का उपयोग करने की ज़रूरत है, तो आपको एक void * user_context तर्क जोड़ना चाहिए ताकि यह कम से कम संभव हो (यद्यपि असुविधाजनक हो) उस स्थिति तक पहुंचने के लिए जो सीधे नहीं है समारोह के लिए पारित कर दिया

std::function से बचने का एकमात्र कारण विरासत के कंपाइलरों का समर्थन है जो इस टेम्पलेट के लिए समर्थन की कमी है, जिसे सी ++ 11 में पेश किया गया है।

यदि प्री-सी +11 भाषा का समर्थन करने की आवश्यकता नहीं है, तो std::function का इस्तेमाल करके कॉलबैक को लागू करने में अधिक विकल्प मिलते हैं, यह "सादे" फ़ंक्शन पॉइंटर्स की तुलना में बेहतर विकल्प बनाते हैं। यह आपके एपीआई के उपयोगकर्ताओं को अधिक विकल्प प्रदान करता है, जबकि कॉलबैक करने वाले आपके कोड के कार्यान्वयन के विशेषताओं को अलग करते हुए।

std::function VMT कोड को कुछ मामलों में ला सकता है, जो प्रदर्शन पर कुछ प्रभाव पड़ता है।