2012-09-17 13 views
9

Internets'teki bazı kaynaklar (özellikle this one) std :: işlevinin küçük kapanma optimizasyonlarını kullandığını, ör. kapatma boyutu bazı verilerin miktarı düşükse o yığın tahsis yok g ++: std :: işlevi kapatma türü ile başlatılan her zaman yığın ayırma kullanır?

Yani böyle optimizasyon karar verilir uygulandığı olsun veya olmasın gibi

görünüyor ++ başlıkları g ile kazma gitti (Yukarıdaki bağlantı gcc için 16 bayt gösterir)

_Local_storage()
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)); } 
    }; 

örneğin ise, "işlevsel" başlığı (g ++ 4.6.3)

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

bu kod bloğu ve aşağı doğru bir çizgi ile Sonunda

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)); 

ve: __stored_locally

typedef integral_constant<bool, __stored_locally> _Local_storage; 

ve: __is_location_invariant:

template<typename _Tp> 
struct __is_location_invariant 
: integral_constant<bool, (is_pointer<_Tp>::value 
       || is_member_pointer<_Tp>::value)> 
{ }; 
- true_type, yerleşim yeni denir daha aksi _Local_storage düzenli yeni

Definition folowing olduğunu

So. Anlatabildiğim kadarıyla, kapanış tipi ne bir işaretçi ne de bir üye işaretçisidir.

#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; 
} 

ve çıkış geçerli:: Hatta küçük bir test programı yazdım doğrulamak için intializing olduğu std :: lambda'da fonksiyon daima yığın ile sonuçlanır:

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

, sorularım şudur tahsis? ya da bir şey mi eksik?

+0

: http://ideone.com/kzae6U Sen clang kontrol edebilirsiniz (http:

Çeşitli derleyicilerde davranışını kontrol etmek için basit program yazabilirsiniz // melpon.org/wandbox/) aynı programın sadece çok büyük yakalama için bellek ayırma yaptığı ... – PiotrNycz

cevap

1

std :: işlevinin bir uygulama ayrıntısıdır; ancak son kontrol ettim, 12 bayt msvc için max functor boyutu, gcc için 16, boost + msvc için 24.

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

geri alacağı:

std::__is_location_invariant: 0 

En azından bu ne ideone says var

+0

adzm: evet, bu sorunun başındaki bağlantıdan bahsedilir. Ancak, aslında g ++ –

2

Bunu ekledi eğer bahis.

+0

ile durumun bu olduğunu görmüyorum Evet, bu benim denememden oldukça ima ediyor. Soru: bu son mu? Dobbs yanlış ve her zaman yığın ayırmalarımız var mı? –

+0

@AlexI., Gerçekten derleyiciye bağlı. – MSN

7

GCC 4.8.1'deki gibi, std :: işlevi, libstdC++ içindeki işlevler ve yöntemler için yalnızca işaretçiler için en iyi duruma getirir. Dolayısıyla, func'inizin boyutu (lambda dahil) ne olursa olsun, bir std :: işlevini baştan başlatarak, yığın ayırmayı tetikler. Ne yazık ki, özel ayırıcılar için de destek yoktur.

Visual C++ 2012 ve LLVM libC++ yeterince küçük bir functor için ayırmayı önler.

Not: Bu optimizasyonun functor'ına basması için std :: is_nothrow_move_constructible öğesinin yerine getirilmesi gerekir. Bu, noexcept std :: function :: swap() öğesini desteklemektir. Neyse ki, tüm yakalanan değerler varsa lambda bu ihtiyacı karşılar.

Bu programdan ederek bulgularını teyit
#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; 
} 
İlgili konular