2017-03-07 3 views
12

मेरे पास एक फ़ंक्शन पर इशारा करते हुए std::function है। इस फ़ंक्शन के अंदर मैं सूचक को दूसरे फ़ंक्शन में बदल देता हूं।क्या फ़ंक्शनपोइंटर (std :: function) को कॉल किए गए फ़ंक्शन के अंदर बदलना सुरक्षित है?

std::function<void()> fun; 

void foo() { 
    std::cout << "foo\n"; 
} 

void bar() { 
    std::cout << "bar\n"; 
    fun = foo; 
} 

int main() { 
    fun = bar; 
    fun(); 
    fun(); 
} 

मुझे कोई समस्या नहीं देख सकते हैं और यह सिर्फ ठीक काम करता है (here देखें), हालांकि मुझे यकीन है कि अगर यह ऐसा करने के लिए कानूनी है नहीं कर रहा हूँ। क्या ऐसा कुछ भी है जिसे मैं ऐसा नहीं कर रहा हूं (शायद सी ++ मानक मसौदे में (मैंने जल्दी से जांच की लेकिन अब तक कुछ भी नहीं देखा))?

+6

इसमें कुछ भी गलत नहीं है। बस। –

+1

कानूनी लेकिन खराब शैली, वैश्विक चर की स्थिति को नियंत्रित करने के लिए कड़ी मेहनत के कारण (जिसे आपको किसी भी तरह से बचने की कोशिश करनी चाहिए)। – Aziuth

+0

मेरे पास एक मिनी गेम प्रोजेक्ट है जहां मैं 'std :: function' का उपयोग मुख्य लूप कॉलबैक (जिसे 60 गुना/सेकेंड कहा जाता है) के रूप में उपयोग करता है और इसे गेम स्टेटस (मेनू चयन, प्लेइंग, पॉज़िंग इत्यादि) को बदलने के लिए अलग-अलग तरीकों से असाइन किया जाता है। यह ठीक चलाता है। – tntxtnt

उत्तर

10

यह फ़ंक्शन पॉइंटर्स के साथ कानूनी है।

जब आप लक्ष्य के साथ std::function असाइन या निर्माण करते हैं, तो यह लक्ष्य के प्रति कॉपी करता है। std::function पर फ़ंक्शन असाइन करने के मामले में, यह प्रभाव फ़ंक्शन पॉइंटर को लक्षित ऑब्जेक्ट के रूप में संग्रहीत करता है।

जब आप operator() का आह्वान करते हैं, तो क्या होगा यदि आप तर्क के साथ लक्ष्य को आमंत्रित करते हैं तो क्या होगा।

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

फ़ंक्शन पॉइंटर को नष्ट करने से फ़ंक्शन के भीतर निष्पादित कोड की वैधता पर कोई प्रभाव नहीं पड़ता है।

हालांकि, अगर आप रखा था समारोह वस्तुओं (lambdas, मैनुअल लोगों, अन्य std::function रों, std::bind, आदि), असाइनमेंट के अंक आप एक वर्ग जब में एक विधि चल के सामान्य नियमों में चलाने चाहते हैं पर this नष्ट हो गया है। संक्षेप में, अब आप अपने उदाहरण के "स्थानीय राज्य" पर निर्भर कुछ भी करने में सक्षम नहीं होंगे।

std::function<void()> fun; 
struct bob { 
    std::string name; 
    bob* next = 0; 
    void operator()() const { 
    std::cout << name << "\n"; 
    if (next) fun = *next; 
    // undefined behavior: 
    // std::cout << name << "\n"; 
    } 
}; 
bob foo = {"foo"}; 
bob bar = {"bar", &foo}; 

int main() { 
    fun = bar; 
    fun(); 
    fun(); 
} 

live example

तो जैसा कि आप देख सकते हैं, यह नाजुक हो सकता है।

-1

यदि आप उचित विचार किए बिना और कोड दस्तावेज़ में ऐसा करते हैं तो यह आपको वापस करने के लिए वापस आ सकता है, लेकिन कोई तर्कसंगत कारण नहीं है कि यह क्यों काम नहीं करेगा।

सी ++ में, फ़ंक्शन कोडिंग में फ़ंक्शन के भीतर फ़ंक्शन का पता आवश्यक नहीं है।

यदि यह कुछ भाषा में काम नहीं करता है तो शिकायतकर्ता शायद इसे स्वीकार नहीं करेगा - अगर यह आधा सभ्य संकलक है।

+2

सामान्य में अंतिम वाक्य से सहमत नहीं होगा। किसी अन्य मामले में, यह अपरिभाषित व्यवहार हो सकता है कि संकलक प्रोग्रामर की तरह संभाल सकता है लेकिन अभी भी अनिर्धारित है। – Aziuth

+0

एक आधा सभ्य संकलक कुछ स्वीकार नहीं करेगा जहां व्यवहार को अपरिभाषित किया जा सकता है। सी कंपाइलर्स द्वारा चलाए गए वर्षों में सबसे भयानक कोड स्वीकार किया जाएगा।सौभाग्य से, अधिकांश सी ++ कंपाइलर्स एक बहुत ही सौदा कठोर हैं। – Quandon

+0

एक सभ्य संकलक आपको '* nullptr' संकलित करने देगा ... – YSC

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