2012-09-17 17 views
9

इन्टरनेट (विशेष रूप से this one) पर कुछ सूत्रों का कहना है कि std :: समारोह छोटे बंद अनुकूलन, उदा का उपयोग यह ढेर आवंटित नहीं है, तो बंद आकार डेटा के कुछ राशि से कम है (यदि उपरोक्त लिंक जीसीसी के लिए 16 बाइट्स इंगित करता है)जी ++: std :: समारोह बंद प्रकार के साथ प्रारंभ हमेशा ढेर आवंटन का उपयोग करता है?

तो मैं जी के माध्यम से खुदाई ++ हेडर

लग रहा है इस तरह के अनुकूलन या नहीं, की तरह का फैसला किया है लागू किया जाता है के लिए चला गया

static void 
_M_init_functor(_Any_data& __functor, _Functor&& __f, true_type) 
{ new (__functor._M_access()) _Functor(std::move(__f)); } 

static void 
_M_init_functor(_Any_data& __functor, _Functor&& __f, false_type) 
{ __functor._M_access<_Functor*>() = new _Functor(std::move(__f)); } 
    }; 

जैसे _Local_storage() है यदि: में "कार्यात्मक" शीर्षक (छ ++ 4.6.3)

static void 
_M_init_functor(_Any_data& __functor, _Functor&& __f) 
{ _M_init_functor(__functor, std::move(__f), _Local_storage()); } 

कोड के इस ब्लॉक और नीचे कुछ लाइनों से

typedef integral_constant<bool, __stored_locally> _Local_storage; 

और __stored_locally:

static const std::size_t _M_max_size = sizeof(_Nocopy_types); 
static const std::size_t _M_max_align = __alignof__(_Nocopy_types); 

static const bool __stored_locally = 
(__is_location_invariant<_Functor>::value 
&& sizeof(_Functor) <= _M_max_size 
&& __alignof__(_Functor) <= _M_max_align 
&& (_M_max_align % __alignof__(_Functor) == 0)); 

और अंत में: __is_location_invariant:

template<typename _Tp> 
struct __is_location_invariant 
: integral_constant<bool, (is_pointer<_Tp>::value 
       || is_member_pointer<_Tp>::value)> 
{ }; 
- true_type, की तुलना में स्थान-नई कहा जाता है, अन्यथा _Local_storage का नियमित रूप से नए

defintion folowing है

So. जहां तक ​​मैं कह सकता हूं, बंद करने का प्रकार न तो एक सूचक है और न ही सदस्य सूचक है। सत्यापित करने के लिए कि मैं भी एक छोटे से परीक्षण कार्यक्रम ने लिखा है:

#include <functional> 
#include <iostream> 

int main(int argc, char* argv[]) 
{ 
    std::cout << "max stored locally size: " << sizeof(std::_Nocopy_types) << ", align: " << __alignof__(std::_Nocopy_types) << std::endl; 

    auto lambda = [](){}; 

    typedef decltype(lambda) lambda_t; 

    std::cout << "lambda size: " << sizeof(lambda_t) << std::endl; 
    std::cout << "lambda align: " << __alignof__(lambda_t) << std::endl; 

    std::cout << "stored locally: " << ((std::__is_location_invariant<lambda_t>::value 
    && sizeof(lambda_t) <= std::_Function_base::_M_max_size 
    && __alignof__(lambda_t) <= std::_Function_base::_M_max_align 
    && (std::_Function_base::_M_max_align % __alignof__(lambda_t) == 0)) ? "true" : "false") << std::endl; 
} 

और आउटपुट है: intializing है std :: लैम्ब्डा के साथ समारोह हमेशा ढेर के साथ परिणाम:

max stored locally size: 16, align: 8 
lambda size: 1 
lambda align: 1 
stored locally: false 

तो, मेरे सवालों का पीछा कर रहा है आवंटन? या क्या मैं कुछ न कुछ भूल रहा हूं?

+0

मैं इस कार्यक्रम के द्वारा अपने निष्कर्षों की पुष्टि: http://ideone.com/kzae6U आप बजना पर जांच कर सकते हैं (http:

आप विभिन्न compilers पर व्यवहार की जांच करने के लिए एक साधारण प्रोग्राम लिख सकते हैं // melpon.org/wandbox/) कि एक ही प्रोग्राम केवल बहुत बड़े कैप्चर के लिए स्मृति आवंटन करता है ... – PiotrNycz

उत्तर

1

std :: समारोह का आवंटन एक कार्यान्वयन विस्तार है, हालांकि मैंने पिछली बार जांच की, 12 बाइट्स एमएसवीसी के लिए अधिकतम मज़ेदार आकार, जीसीसी के लिए 16, बूस्ट + एमएसवीसी के लिए 24 है।

+0

adzm: हाँ, प्रश्न की शुरुआत में लिंक में इसका उल्लेख है। हालांकि, मुझे नहीं लगता कि यह वास्तव में g ++ –

2

मैं शर्त लगा सकता है अगर आप इस कहा:

std::cout << "std::__is_location_invariant: " << std::__is_location_invariant<lambda_t>::value << std::endl; 

तुम वापस मिलेगा:

std::__is_location_invariant: 0 

कम से कम है कि क्या ideone says है।

+0

हां के साथ मामला है, यह मेरे परीक्षण से काफी अधिक है। प्रश्न यह है: यह अंतिम है? डॉ। डॉब्स गलत है और हम हमेशा ढेर आवंटन करते हैं? –

+0

@AlexI।, यह वास्तव में संकलक पर निर्भर करता है। – MSN

7

जीसीसी 4.8.1 के रूप में, std :: libstdc में समारोह ++ केवल कार्य करता है और तरीकों की ओर इशारा करने के लिए अनुकूलित करता है। तो चाहे आपके मज़ेदार (लैम्बडास शामिल) का आकार, एक std :: फ़ंक्शन प्रारंभ करने से ही ढेर आवंटन ट्रिगर हो जाता है। दुर्भाग्यवश कस्टम आवंटकों के लिए कोई समर्थन नहीं है।

विजुअल सी ++ 2012 और एलएलवीएम libC++ किसी भी पर्याप्त छोटे मज़ेदार के लिए आवंटन से बचें।

ध्यान दें, के लिए इस अनुकूलन अपने functor std :: is_nothrow_move_constructible को पूरा करना चाहिए में किक करने। यह abdcept std :: function :: swap() का समर्थन करने के लिए है। सौभाग्य से, लैम्ब्डा इस आवश्यकता को पूरा करते हैं यदि सभी कब्जे वाले मूल्य करते हैं।

#include <functional> 
#include <iostream> 

// noexpect missing in MSVC11 
#ifdef _MSC_VER 
# define NOEXCEPT 
#else 
# define NOEXCEPT noexcept 
#endif 

struct A 
{ 
    A() { } 
    A(const A&) { } 
    A(A&& other) NOEXCEPT { std::cout << "A(A&&)\n"; } 

    void operator()() const { std::cout << "A()\n"; } 

    char data[FUNCTOR_SIZE]; 
}; 

int main() 
{ 
    std::function<void()> f((A())); 
    f(); 

    // prints "A(A&&)" if small functor optimization employed 
    auto f2 = std::move(f); 

    return 0; 
} 
संबंधित मुद्दे