12

メモリ内で任意の型の配列が続くクラスを実装しようとしています。

template<class T>
class Buf
{
    size_t n;
    int refs;
    explicit Buf(size_t n) : n(n) { }
    // other declarations are here as appropriate

    // Followed in memory by:
    // T items[n];
};

これは簡単operator newです:

template<class T>
Buf<T> *make_buf(size_t n)
{
    // Assume the caller will take care of constructing the array elements
    return new(operator new(sizeof(Buf<T>) + sizeof(T) * n)) Buf<T>(n);
}

template<class T>
void free_buf(Buf<T> *p)
{
    // Assume the caller has taken care of destroying the array elements
    p->~Buf<T>();
    return operator delete(p);
}

template<class T>
T *get_buf_array(Buf<T> *p)
{
    return reinterpret_cast<T *>(reinterpret_cast<char *>(p) + sizeof(Buf<T>));
}

しかし今、標準に準拠したallocator を使用してこれを実装するにはどうすればよいSomeAllocatorですか?

SomeAllocator::rebind<char>::other::allocateどのタイプのオブジェクトにも適切に整列されたメモリを返すことが保証されていますか? もしそうなら、char型のアロケータを使用するだけで安全ですか? そうでない場合、代替手段はありますか、それとも一般的にアロケーターではこのタスクは不可能ですか? (最悪の場合、ポインタをuintptr_t手動でキャストして整列させることができると思いますが、もっと良い方法があるかどうか疑問に思っています。)

4

4 に答える 4

1

概念的な初期配列を作成することで解決できると考えていました。

+-----------+
|Buf<T>     |
+-------+---+---+-------+-------+
|T[0]   | T[1]  |T[2]   |  T[3]...
+-------+-------+-------+-------+

With the non-overlapping T[2], T[3], ... being the required array of T.

template<class T>
class Buf
{
    size_t n;
    int refs;
    explicit Buf(size_t n) : n(n) { }
    // other declarations are here as appropriate

    // Followed in memory by:
    // T items[n];
};

台無しにされた要素の数は次のようになります:-

const size_t lead = ( sizeof(Buf<T>) + sizeof(T) - 1) / sizeof(T);

最後に、i の生メモリにアクセスできます。

(reinterpret_cast<T*>( this ) )[ i + lead ];
于 2015-12-31T20:22:01.467 に答える
0

C++ 標準が必要とするものについて、不当な仮定をしているのではないでしょうか。あなたがやろうとしていることは、一般的には不可能かもしれません。

デフォルトのアロケータ (new または malloc) は、適切にアラインされたメモリ ブロックへのポインタを返すために必要ですany complete object type with a fundamental alignment requirement。サイズは でなければなりませんat least as large as the requested size。カスタム アロケータには、割り当てる対象に応じてさまざまな要件があります。あるタイプのアロケーターが、別のタイプに適切にアラインされたストレージを返すことは保証されていません。もちろん、カスタム アロケーターを実装している場合は、必要なものが確実に返されるようにすることができます。

コンパイラは、メモリ レイアウトに関するいくつかの制約を満たす必要がありますが、何かが他のものの直後にメモリに配置されることは保証されません。アラインメント要件を満たすために、パディング バイトが挿入される場合があります。

最近の C++ 標準では、アラインメントの処理がかなりサポートされています。あなたの答えはきっとどこかにあるはずです。これの根底には、あなたが私たちに話していないいくつかの要件があると思います。おそらく、それについて別の方法があります。

于 2014-08-04T03:59:43.873 に答える
0

標準準拠のアロケータは準拠していると思いますか? アロケータを stl データ構造で使用する必要がないので、実際にはその要件を満たす必要はありません。カスタム stl スタイル アロケータをテンプレート パラメータとして std::vector を使用してバッファを実装します。operator new と operator new[] のアラインメントの保証に関しては、以下をご覧になることをお勧めします。

C++ の新しい操作によるアドレス リターンのアラインメントの保証はありますか? .

アラインメントの懸念が double などのプリミティブ型に関するものである場合、 http://en.cppreference.com/w/cpp/memory/alignでわかるように、 std::align でほぼカバーされます。

ただし、すべての要素をキャッシュラインなどにアラインするなど、見知らぬ/より大きなアラインメント要件がある場合、または T が sizeof(T)mod アライメント != 0 のサイズの型である場合、T の配列を割り当てるときに問題が発生する可能性があります。このような場合、配列の最初の要素が要件を満たすように整列されていても、後続のすべての要素も整列されるとは限りません。

于 2014-10-02T10:49:38.233 に答える
0

アロケータを の特殊化に再バインドすることにより、アラインメントを制限しますstd::aligned_storage

typedef std::aligned_storage_t< 1, std::max( alignof (Buf<T>), alignof (T) ) >
        unit_type; // lowest-common-denominator type for aligned allocation

std::size_t unit_count // number of unit_type array elements needed
    = ( sizeof (Buf<T>) + sizeof (T) * n // = actual used storage
           + sizeof (unit_type) - 1 )    //   + alignment padding
      / sizeof (unit_type);              // divided by element size

typedef typename std::allocator_traits< SomeAllocator >::rebind_alloc< unit_type >
        rebound;

rebound a( alloc_parm ); // Retain this somewhere if statefulness is allowed.
ptr = std::allocator_traits< rebound >::allocate( a, unit_count );

(すべてのアロケータ アクセスが通過することを忘れないでくださいallocator_traits!)

于 2015-06-13T07:01:54.477 に答える