2013-03-19 7 views
9

私の質問はかなり単純です。alignas指定子は 'new'で動作しますか?

alignas指定子は 'new'で使用できますか?つまり、構造体が整列するように定義されている場合、新しい構造体が割り当てられると整列されますか?

答えて

14

タイプの配置が過ぎていない場合は、デフォルトのnewが有効になります。 「オーバーライドされた」とは、alignasで指定したアラインメントがalignof(std::max_align_t)より大きいことを意味します。デフォルトのnewは、偶然によって多少なりとも整列していないタイプでも動作します。デフォルトのメモリアロケータは、常にアラインメントがalignof(std::max_align_t)に等しいメモリを割り当てます。

あなたのタイプのアライメントがオーバーアライメントされている場合は、不運です。デフォルトのnewもグローバルnew演算子も、タイプに必要な配置を知ることはできず、それに適したメモリを割り当てるだけではありません。このケースを助ける唯一の方法は、クラスのoperator newをオーバーロードすることです。クラスのアライメントにalignofを照会することができます。

もちろん、このクラスが別のクラスのメンバーとして使用されている場合は、これは役に立ちません。その他のクラスもまたoperator newをオーバーロードしない限り。したがって、new pair<over_aligned, int>()のような単純なものは機能しません。

operator new/deleteのオーバーロードが割り当てられるタイプのalignofを持つことによって、(受け入れられた)C++ 17の提案では、support for dynamic allocation of over-aligned typesが追加されます。これは、最大整列型よりも小さい整列もサポートします。したがって、メモリアロケータは必ずalignof(std::max_align_t)に整列されたメモリを返す必要はありません。

つまり、コンパイラはが必要です。オーバーライドされた型をまったくサポートするには、が必要です。

+4

追加するには: alignof(std :: max_align_t) 'です。これよりも大きなアラインメントを持つ型は* over-aligned *と呼ばれ、それらのサポートは条件定義であり、実装定義です。 – GManNickG

+0

私は実際にこれを必要としませんが、とにかく知っていいですね! – Skeen

+0

上限を上げるために何かできますか? – Skeen

7

いいえ、それはありません。構造体は要求された配置にパディングされますが、配置されません。しかし、これがallowed in C++17になる可能性があります(このC++ 17の提案が存在するということは、これがC++ 11ではうまくいかないことを証明するはずです)。

私はこれがいくつかのメモリアロケータで動作するように見えましたが、それは純粋に幸運でした。例えば、メモリアロケータの中には、アロケータの最適化として要求されたサイズ(最大4KB)の2の累乗にメモリアロケータを合わせるものがあります(メモリの断片化を減らし、以前に解放されたメモリなどを再利用しやすくする) 。しかし、私がテストしたOS X 10.7とCentOS 6システムに含まれている新しい/ mallocの実装は、これをしておらず、次のコードで失敗します:

#include <stdlib.h> 
#include <assert.h> 

struct alignas(8) test_struct_8 { char data; }; 
struct alignas(16) test_struct_16 { char data; }; 
struct alignas(32) test_struct_32 { char data; }; 
struct alignas(64) test_struct_64 { char data; }; 
struct alignas(128) test_struct_128 { char data; }; 
struct alignas(256) test_struct_256 { char data; }; 
struct alignas(512) test_struct_512 { char data; }; 

int main() { 
    test_struct_8 *heap_8 = new test_struct_8; 
    test_struct_16 *heap_16 = new test_struct_16; 
    test_struct_32 *heap_32 = new test_struct_32; 
    test_struct_64 *heap_64 = new test_struct_64; 
    test_struct_128 *heap_128 = new test_struct_128; 
    test_struct_256 *heap_256 = new test_struct_256; 
    test_struct_512 *heap_512 = new test_struct_512; 

#define IS_ALIGNED(addr,size) ((((size_t)(addr)) % (size)) == 0) 

    assert(IS_ALIGNED(heap_8, 8)); 
    assert(IS_ALIGNED(heap_16, 16)); 
    assert(IS_ALIGNED(heap_32, 32)); 
    assert(IS_ALIGNED(heap_64, 64)); 
    assert(IS_ALIGNED(heap_128, 128)); 
    assert(IS_ALIGNED(heap_256, 256)); 
    assert(IS_ALIGNED(heap_512, 512)); 

    delete heap_8; 
    delete heap_16; 
    delete heap_32; 
    delete heap_64; 
    delete heap_128; 
    delete heap_256; 
    delete heap_512; 

return 0; 
} 
+0

これは正しいですが、一番上の答えはありません。 C++ 11 *では、スタックに割り当てられたオブジェクトの整列が正しく行われますが、デフォルトのメモリアロケータでは正しい整列が得られません。 今のところ、OS検出マクロでラップされたPOSIX/windows関数を使用する必要があります。例えば; Linuxの場合はposix_memalign、Windowsの場合はaligned_alloc。インテル®MKLを使用する人には、mkl_mallocとmkl_freeがあります。 – alfalfasprout

関連する問題