2012-09-17 9 views
9

インターネット上のいくつかの情報源(具体的にはthis one)は、std :: functionが小さなクロージャの最適化を使用していると言っています。閉鎖サイズは、データのいくつかの量よりも低い場合には、だから私はg ++:std ::関数はクロージャ型で初期化され、常にヒープ割り当てを使用しますか?

は、このような最適化が適用されているかどうかのように見える++ヘッダグラムを掘り行ってきましたが決定される(上記のリンクは、gccのための16のバイトを示す)

をヒープを割り当てません。 _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)); } 
    }; 

例えば:

"機能" ヘッダ(G ++ 4.6.3)中のコードブロックによって
static void 
_M_init_functor(_Any_data& __functor, _Functor&& __f) 
{ _M_init_functor(__functor, std::move(__f), _Local_storage()); } 

といくつかの行ダウン配置 - 新がそうでない場合、呼び出されたよりもtrue_type、 - _Local_storageの定期的な新しい

defintionはfolowingさ:

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

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:

さまざまなコンパイラで動作を確認するための簡単なプログラムを書くことができます// melon.org/wandbox/)同じプログラムが非常に大きなキャプチャのためのメモリ割り当てしかしないということです。 – PiotrNycz

答えて

1

std :: functionの割り当ては実装の詳細です。しかし、私は最後にチェックしました.12バイトはmsvcの最大ファンクタサイズで、16はgcc、24はboost + msvcです。

+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

はい、それは私のテストからの意味です。質問です:これは最終的なものですか? Dobbs博士は間違っており、常にヒープ割り当てをしていますか? –

+0

@AlexI。それは本当にコンパイラに依存します。 – MSN

7

GCC 4.8.1から、libstdC++のstd ::関数は関数とメソッドへのポインタのみを最適化します。したがって、ファンクタ(ラムダを含む)のサイズにかかわらず、そこからstd ::関数を初期化すると、ヒープ割り当てがトリガされます。残念ながらカスタムアロケータのサポートもありません。

Visual C++ 2012およびLLVM libC++は、十分に小さなファンクタの割り当てを避けます。

注:この最適化のために、ファンクタをキックするには、std :: is_nothrow_move_constructibleを満たす必要があります。これは、noexcept 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; 
} 
関連する問題