2011-12-31 13 views
5

मैं इस तरह एक समारोह है कहते हैं:क्या कोई बढ़ावा :: फ़ंक्शन की प्रतिलिपि बंद करने की प्रतिलिपि बनाता है?

void someFunction(const ExpensiveObjectToCopy&); 

अगर मैं एक बढ़ावा :: समारोह बाहर अगर यह, कि समारोह के बंद होने में वस्तु का अपना क्लोन प्रतिलिपि संग्रहीत करना होगा:

boost::function<void()> f = boost::bind(someFunction, x); // <-- f saves a copy of x 

अब अगर मैं चारों ओर घूमना शुरू करता हूं, तो क्या बढ़ावा देगा :: फ़ंक्शन कॉपी कन्स्ट्रक्टर प्रतिलिपि जो हर बार फिर से ऑब्जेक्ट करती है, या क्या प्रत्येक फ़ंक्शन एक ही बंद हो जाता है? (अर्थात इस तरह)

boost::function<void()> f2 = f; 
callSomeFunction(f); 
etc. 

उत्तर

4

क्या मैं (वास्तव में आसान नहीं स्रोत का एक सरसरी पढ़ने और कुछ प्रयोगों से आंकना) प्राप्त कर सकते हैं यह क्लोन वस्तु हर बार की प्रतिलिपि बनाएगा से। यह कार्यद्वारा इसे तर्क के मामले में अनावश्यक हो सकता है, लेकिन सामान्य रूप से ऑब्जेक्ट को फ़ंक्शन द्वारा उत्परिवर्तित किया जा सकता है। यदि वस्तु कॉपी करने के लिए महंगा है, यह समझ बनाने के संदर्भ (boost::ref या boost::cref दिमाग में आते हैं) या द्वारा यह कब्जा करने के लिए नहीं होता, यदि मूल वस्तु मंगलाचरण के बिंदु पर मौजूद नहीं है, एक boost::shared_ptr को पकड़ने और एक एडाप्टर बारे में विधि, जो smartpointer unpacks और someFunction पर कॉल करता है?

संपादित करें: प्रयोग से न केवल boost::function की प्रतिलिपि बनाई गई है, लेकिन यह boost::bind के अंदर कई बार प्रतिलिपि बनायेगी।

struct foo_bar { 
    std::vector<int> data; //possibly expensive to copy 
    foo_bar() 
    { std::cout<<"default foo_bar "<<std::endl; } 
    foo_bar(const foo_bar& b):data(b.data) 
    { std::cout<<"copy foo_bar "<<&b<<" to "<<this<<std::endl; } 
    foo_bar& operator=(const foo_bar& b) { 
     this->data = b.data; 
     std::cout<<"asign foo_bar "<<&b<<" to "<<this<<std::endl; 
     return *this; 
    } 
    ~foo_bar(){} 
}; 

void func(const foo_bar& bar) { std::cout<<"func"<<std::endl;} 

int main(int, char*[]) { 
    foo_bar fb; 
    boost::function<void()> f1(boost::bind(func, fb)); 
    std::cout<<"Bind finished"<<std::endl; 
    boost::function<void()> f2(f1); 
    std::cout<<"copy finished"<<std::endl; 
    f1(); 
    f2(); 
    return 0; 
} 

जिसके परिणामस्वरूप उत्पादन पीछा किया जाता है के रूप में: मैं जीसीसी 4.6 और -O2 (और -std = C++ 0x) के साथ MinGW 32 के अंतर्गत निम्नलिखित कोड बढ़ावा 1.45 का उपयोग कर का उपयोग कर परीक्षण किया

default foo_bar 
copy foo_bar 0x28ff00 to 0x28ff10 
copy foo_bar 0x28ff10 to 0x28ff28 
copy foo_bar 0x28ff28 to 0x28ff1c 
copy foo_bar 0x28ff1c to 0x28ff34 
copy foo_bar 0x28ff34 to 0x28fed4 
copy foo_bar 0x28fed4 to 0x28fee4 
copy foo_bar 0x28fee4 to 0x28fef4 
copy foo_bar 0x28fef4 to 0x28fe14 
copy foo_bar 0x28fe14 to 0x28fe24 
copy foo_bar 0x28fe24 to 0x28fe34 
copy foo_bar 0x28fe34 to 0x6a2c7c 
Bind finished 
copy foo_bar 0x6a2c7c to 0x6a2c94 
copy finished 
func 
func 

इसलिए कॉपी कन्स्ट्रक्टर को बाईंडिंग और एफ 1 के लिए असाइनमेंट के लिए एक बार और 11 बार बनाने के लिए बुलाया गया था। चूंकि पहली वस्तु स्टैक पर बनाई गई है और प्रतियों के पते उस के बहुत करीब हैं और थोड़ा बढ़ रहे हैं, ऐसा लगता है कि बाध्यकारी प्रक्रिया बहुत से कार्यों से गुज़रती है, जो संकलक इस मामले में इनलाइन नहीं करता है और प्रत्येक ऑब्जेक्ट को मूल्य के साथ पास करें। बस boost::bind कहीं भी परिणाम सहेजे बिना उपयोग करना:

int main(int, char*[]) { 
    foo_bar fb; 
    boost::function<void()> f1(boost::bind(func, fb)); 
    return 0; 
} 

default foo_bar 
copy foo_bar 0x28ff00 to 0x28ff10 
copy foo_bar 0x28ff10 to 0x28ff28 
copy foo_bar 0x28ff28 to 0x28ff1c 
copy foo_bar 0x28ff1c to 0x28ff34 
copy foo_bar 0x28ff34 to 0x28fef4 

तो पांच प्रतियां सिर्फ वस्तु बाध्य करने के लिए। इसलिए मैं सामान्य रूप से कोड के किसी भी दूरस्थ रूप से प्रदर्शन संवेदनशील हिस्सों में प्रति मूल्य कम से कम मध्यम प्रति लागत लागत को कैप्चर करने से बचूंगा। तुलना gccs में std::tr1::bind और std::bind ज्यादा (std :: tr1 :: समारोह/std :: समारोह के साथ) का बेहतर प्रदर्शन (कोड मूल रूप से पहले testcode के समान है, सिर्फ विकल्प boost:: क्रमशः std::tr1:: साथ std:::

std::tr1::bind with std::tr1::function: 
default foo_bar 
copy foo_bar 0x28ff10 to 0x28ff28 
copy foo_bar 0x28ff28 to 0x28ff34 
copy foo_bar 0x28ff34 to 0x28ff04 
copy foo_bar 0x28ff04 to 0x652c7c 
Bind finished 
copy foo_bar 0x652c7c to 0x652c94 
copy finished 
func 
func 

std::bind with std::function: 
default foo_bar 
copy foo_bar 0x28ff34 to 0x28ff28 
copy foo_bar 0x28ff28 to 0x3c2c7c 
Bind finished 
copy foo_bar 0x3c2c7c to 0x3c2c94 
copy finished 
func 
func 

मुझे लगता है कि std::bind या तो आंतरिक आमंत्रण के लिए कॉन्स्ट रेफ द्वारा गुजरता है, या इस तरह से लिखा जाता है कि जीसीसी इनलाइनर के लिए कुछ अनुकूल है और अनावश्यक प्रतिलिपि बनाने वालों को खत्म करने के लिए अधिक अनुकूल है। tr1::bind तब भी boost::bind को बेहतर अनुकूलित किया जाता है, लेकिन अभी भी इष्टतम से दूर है।

बेशक हमेशा इस तरह के परीक्षणों के साथ वाईएमएमवी विभिन्न संकलन झंडे/कंपाइलर्स

+0

से बाहर आता है जब g(const a &) के माध्यम से ff() या ff2()

  • नाशक कहा जाता है कहा जाता है कहा जाता है मैं एक परीक्षण कार्यक्रम में लिखा था और इसे संग्रहीत वस्तु के प्रति निर्माता की तरह दिखता है हर बार जब आप कॉपी समारोह वस्तु कहा जाता हो जाता है । इसके अलावा, बूस्ट :: बाइंड प्रतिलिपि बनाने वाले 11 बार कॉल करता है! – Chris

  • +0

    @ क्रिस: ठीक है, तो मेरा परीक्षण जानना अच्छा नहीं था। तो अगर कोई सी ++ 11 का उपयोग कर सकता है तो ऐसा लगता है कि std :: बाइंड एक बहुत ही मार्जिन से जाने का तरीका है (हालांकि व्यक्तिगत रूप से मैं इसके बजाय लैम्बडा का उपयोग करता हूं)। – Grizzly

    3

    यदि आप bind पर मूल्य से ऑब्जेक्ट पास करते हैं तो यह कॉपी हो जाता है (जैसा आपने परीक्षण किया: 11 बार)।

    लेकिन यदि आप प्रतिलिपि बनाना नहीं चाहते हैं तो इसे संदर्भ (boost::cref का उपयोग करके) पास करें और इसकी प्रतिलिपि नहीं बनाई गई है।

    struct a 
    { 
        a() { std::cout << __func__ << std::endl; } 
        a(const a &) { std::cout << __func__ << std::endl; } 
        ~a() { std::cout << __func__ << std::endl; } 
        const a & operator=(const a & aa) 
        { std::cout << __func__ << std::endl; return aa; } 
    }; 
    
    void g(const a &) { std::cout << __func__ << std::endl; } 
    
    
    void t2() 
    { 
        a aa; 
    
        boost::function< void() > ff = boost::bind(g, boost::cref(aa)); 
        boost::function< void() > ff2 = ff; 
        std::cout << "after ff" << std::endl; 
        ff(); 
        ff2(); 
        std::cout << "after called ff()" << std::endl; 
    } 
    

    उत्पादन:

    a 
    after ff 
    g 
    g 
    after called ff() 
    ~a 
    

    है

    1. एक निर्माता कहा जाता है जब वस्तु
    2. कोई निर्माता जब समारोह वस्तु ff बनाने या इसकी एक प्रति बनाने बुलाया बनाया (ff2)
    3. कोई कन्स्ट्रक्टर नहीं जब वस्तु गुंजाइश
    संबंधित मुद्दे

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