次の合法的なC++は、明確に定義された動作をしていますか?
class my_class { ... };
int main()
{
char storage[sizeof(my_class)];
new ((void *)storage) my_class();
}
または、これはポインタのキャスト/配置の考慮事項のために問題がありますか?
次の合法的なC++は、明確に定義された動作をしていますか?
class my_class { ... };
int main()
{
char storage[sizeof(my_class)];
new ((void *)storage) my_class();
}
または、これはポインタのキャスト/配置の考慮事項のために問題がありますか?
はい、問題があります。メモリが適切に配置されているという保証はありません。
aligned_storage
適切な配置でストレージを取得するためのさまざまなトリックが存在しますが、これらのトリックを隠すBoostまたはC++0xを使用することをお勧めします。
次に、必要なのは次のとおりです。
// C++0x
typedef std::aligned_storage<sizeof(my_class),
alignof(my_class)>::type storage_type;
// Boost
typedef boost::aligned_storage<sizeof(my_class),
boost::alignment_of<my_class>::value>::type storage_type;
storage_type storage; // properly aligned
new (&storage) my_class(); // okay
C ++ 0xでは、属性を使用して、次のことを実行できることに注意してください。
char storage [[align(my_class)]] [sizeof(my_class)];
ここで言及されているように、これは配置の制限のために必ずしも機能するとは限りません。位置合わせを正しく行うには、いくつかの方法があります。まず、C ++ 0x準拠のコンパイラを使用している場合は、alignof演算子を使用して、整列を強制的に正しくすることができます。次に、文字配列を動的に割り当てることができます。これは、演算子newからのメモリが、すべての人が正しく使用できるように整列されることが保証されているためです。第3に、システム上で可能な限り最大の配置を持つタイプのユニオンに文字配列を格納してみることができます。この記事にはいくつかの情報があると思います(ただし、C ++ 03用に設計されており、間もなくリリースされるalignof演算子ほど良くはありません)。
お役に立てれば!
BoostやC++1xを避けたい場合は、この完全なコードがGCCとMSVCの両方で機能します。MSVC固有のコードは、Chromiumのaligned_memory.hに基づいています。MSVCはリテラルの配置値のみを受け入れるため、GCCバージョンよりも少し複雑です__declspec(align(.))
。これは、すべての可能な配置に対してテンプレートの特殊化を使用して回避されます。
#ifdef _MSC_VER
template <size_t Size, size_t Align>
struct AlignedMemory;
#define DECLARE_ONE_ALIGNED_MEMORY(alignment) \
template <size_t Size> \
struct __declspec(align(alignment)) AlignedMemory<Size, alignment> { \
char mem[Size]; \
};
DECLARE_ONE_ALIGNED_MEMORY(1)
DECLARE_ONE_ALIGNED_MEMORY(2)
DECLARE_ONE_ALIGNED_MEMORY(4)
DECLARE_ONE_ALIGNED_MEMORY(8)
DECLARE_ONE_ALIGNED_MEMORY(16)
DECLARE_ONE_ALIGNED_MEMORY(32)
DECLARE_ONE_ALIGNED_MEMORY(64)
DECLARE_ONE_ALIGNED_MEMORY(128)
DECLARE_ONE_ALIGNED_MEMORY(256)
DECLARE_ONE_ALIGNED_MEMORY(512)
DECLARE_ONE_ALIGNED_MEMORY(1024)
DECLARE_ONE_ALIGNED_MEMORY(2048)
DECLARE_ONE_ALIGNED_MEMORY(4096)
#else
template <size_t Size, size_t Align>
struct AlignedMemory {
char mem[Size];
} __attribute__((aligned(Align)));
#endif
template <class T>
struct AlignedMemoryFor : public AlignedMemory<sizeof(T), __alignof(T)> {};
アライメントのために少なくとも問題があります。
ほとんどの非Intelアーキテクチャでは、アラインメントが間違っているためにコードが「バスエラー」を生成するか、アラインメントされていないメモリアクセスを修正するためにプロセッサトラップが必要なために非常に遅くなります。
Intelアーキテクチャでは、これは通常、通常よりも少し遅くなります。一部のSSE操作が関係している場合を除いて、クラッシュする可能性もあります。
のchar
サイズに対して、配列が正しく整列されていない可能性がありますmyclass
。一部のアーキテクチャでは、アクセスが遅くなることを意味し、他のアーキテクチャでは、クラッシュを意味します。の代わりに、のいずれかのメンバーの最大の配置要件によって与えられる、の配置char
以上の配置を持つタイプを使用する必要があります。struct
#include <stdint.h>
class my_class { int x; };
int main() {
uint32_t storage[size];
new(storage) my_class();
}
1つのインスタンスに十分なメモリを割り当てるには、正しい配置を取得するために使用するタイプはどこであるかを指定する必要があるmy_class
と思います。size
sizeof(my_class) / sizeof(T)
T