Feb. 15, 2011, 11:25 a.m.
posted by virtualbrain
Some hardware architectures impose alignment constraints, requiring that objects of certain types have addresses whose value is a multiple of some small number. In some cases, this is an absolute requirement: Attempting to access data that is not properly aligned causes a hardware fault. In others, it affects program performance: Attempting to access data that is not properly aligned requires additional bus cycles, slowing reading and writing of that data. Since alignment restrictions are imposed by hardware, the small number that defines the required alignment is usually a power of 2: typically, 4, 8, or 16. When we talk about the required alignment for some type, we usually say that it requires, for example, 8-byte alignment. This means that its address must be a multiple of 8.
template <class Ty> struct alignment_of; template <std::size_t Len, std::size_t Align> struct aligned_storage;
The primary problem that these templates address is the need to create a properly aligned static storage block to use with placement new. This code doesn't necessarily work correctly:
unsigned char data [ sizeof (double)]; double * loc = new (( void *)& data ) double ; * loc = 1.0;
The problem here is that the array data can usually be aligned at a 1-byte boundarythat is, anywhere in memorywhereas the double* returned by placement new must point to memory that is properly aligned for an object of type double, which often requires a 4-byte or 8-byte boundary. The usual solution to this problem is to use a union of eight to ten fundamental types, in the hope that one of them will require the target platform's worst-case alignment; a data array that can hold an object of that type will then be able to hold any data type. This approach has two drawbacks. First, alignment requirements for some types may be more severe than those of the types included in the union. In that case, those types will probably not be suitably aligned. Second, this approach wastes space for types whose alignment requirements are less severe than the worst case provided by the union. The solution using the TR1 alignment templates looks like this:
aligned_storage < sizeof ( double ), alignment_of <double>:: value>:: type data ; double * loc = new ((void *)& data) double; * loc = 1.0;
The definition of data in that code is a bit daunting, so let's look at it piece by piece. First, sizeof(double) is the number of bytes needed to represent a value of type double. Second, alignment_of<double>::value is the required alignment for a value of type double. Those two values are passed as the template arguments Len and Align to the class template aligned_-storage. The resulting template instantiation has a nested type named type that has the required size and alignment. By defining data to be an object of that type, we guarantee that data has the required size and alignment. Since that type is a POD, it has a trivial destructor, so running a destructor on data that doesn't make sense won't cause any problems.