@safe containers with std.experimental.allocator

Andrei Alexandrescu via Digitalmars-d digitalmars-d at puremagic.com
Sat Jan 21 15:24:52 PST 2017


On 1/21/17 5:44 PM, bitwise wrote:
> About alignedMalloc:
>
> In C++ for example, I may want to use a vector full some SIMD type:
>
> class alignas(16) Vec4 {
>     union {
>         struct { float x, y, z, w; };
>         __m128 m;
>     };
> };
>
> std::vector<Vec4> points = { ... };
>
> In C++ however, 'new' does not respect over-alignment:
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0035r2.html
>
> Even if new respected alignment, there is no gauruntee all containers,
> STL or otherwise, would use 'new' as opposed to malloc by default(maybe
> one day?)
>
> So I use a custom aligned allocator:
>
> template <class T, int ALIGN>
> class AlignedAllocator {
>     T* allocate(size_type n) {
>         return (T*)_aligned_malloc(ALIGN, n * sizeof(T));
>     }
> };
>
> SIMD operations(aligned load and store) can now safely be used on the
> contents of the std::vector<Vec4>.
>
> std::vector knows nothing about the alignment of the memory it uses. It
> only knows to call allocate() of whatever allocator it's given. If I had
> an allocator with a function 'alignedAllocate' it wouldn't do any good.
> I believe this is the _correct_ design, and that a container _shouldn't_
> have to know about where from, or what kind of memory it's getting.

I understand. That's a questionable design. It only works by virtue of a 
long-distance convention between the rigged allocator and the element 
type of the vector.

> Considering the above use case, alignedAllocate() is redundant, and
> possibly confusing.

Well, you just made use of it in the rigged allocator.

> About missing alignedDeallocate:
>
> while aligned_alloc(), which works in combination with regular 'free()',
> is supposed to be standard as of C++11, it's still not supported in
> visual studio 2015. Instead, one must use _aligned_malloc, and
> _aligned_free. Passing memory from _aligned_malloc to the regular
> version of free() causes a crash. Thus, different deallocation methods
> are needed for both. Also, there's homegrown aligned_allocate functions
> like the following, which require special deallocation functions because
> of the exta metadata prepended to the memory:
> https://github.com/dlang/phobos/blob/366f6e4e66abe96bca9fd69d03042e08f787d040/std/experimental/allocator/mallocator.d#L134-L134
>
>
> I suppose you could use aligned allocation for _all_ allocations, even
> allocations with default alignment, but that would add extra metadata(at
> least 8 bytes) to _all_ allocations even when its unnecessary.
>
> So a solution could be to include the alignment as a template parameter
> of Mallocator, or provide an second AlignedMallocator(uint). The
> allocate() function of either option would return aligned memory if the
> 'alignment' template parameter was non-default. Then, the idea of memory
> alignment would be abstracted away from the containers themselves.
>
> struct Mallocator(uint alignment = platformAlignment){}){}
> or
> struct AlignedMallocator(uint alignment = platformAlignment){}){}

It seems a matter of time until aligned_alloc gets implemented on Windows.


Andrei




More information about the Digitalmars-d mailing list