Regarding emplace, arrays, and helper functions

Ali Çehreli acehreli at yahoo.com
Thu Aug 29 20:10:17 PDT 2013


On 08/29/2013 05:20 AM, Andrej Mitrovic wrote:

 > The emplace docs state that the chunk where to store the class object
 > instance needs to be aligned to the class type alignment. But it
 > doesn't say much on how to get this alignment from a class (we could
 > add a note about using the classInstanceAlignment template), or even
 > how to use it to create e.g. an array of class objects (not an array
 > of references).
 >
 > Here's how one can run into a problem:
 >
 > -----
 > import std.conv;
 >
 > class C
 > {
 >      this(ubyte b) { _b = b; }
 >      ubyte _b;
 > }
 >
 > void main()
 > {
 >      // 9 bytes (x32), it's not going to align itself properly
 >      enum Size = __traits(classInstanceSize, C);
 >
 >      ubyte[Size][2] buffer;
 >
 >      // off-topic: cast needed -> yet another emplace bug
 >      auto obj1 = emplace!C(buffer[0], cast(ubyte)20);
 >      assert(obj1._b == 20);
 >
 >      auto obj2 = emplace!C(buffer[1], cast(ubyte)20);  // Boom!
 >      assert(obj2._b == 20);
 > }
 > -----
 >
 > On the second emplace call, an exception is thrown:
 >
 > -----
 > std.conv.ConvException at std\conv.d(3832): emplace: Misaligned memory
 > block (0x18FD41): it must be 4-byte aligned for type C
 > -----
 >
 > So one has to figure out how to do alignment properly, but there's no
 > real documentation on how to do it.

I had experimented with this in a chapter (not in English yet):

   http://ddili.org/ders/d/bellek_yonetimi.html

Here are two functions that I have just translated from that page (I see 
that alignedAddress should better be alignUp):

T * alignedAddress(T)(T * candidateAddress)
out (result)
{
     assert((cast(size_t)result % T.alignof) == 0);
}
body
{
     return cast(T*)((cast(size_t)candidateAddress + T.alignof - 1)
                     / T.alignof * T.alignof);
}

size_t paddedSize(T)()
{
     static if (is (T == class)) {
         size_t size = __traits(classInstanceSize, T);

     } else {
         size_t size = T.sizeof;
     }

     return cast(size_t)alignedAddress(cast(T*)size);
}

Now your program works with a single change:

     enum Size = paddedSize!C();

Ali



More information about the Digitalmars-d-learn mailing list