Proposal std::make_shared/std::make_unique respecting alignment.

282 views
Skip to first unread message

Emily

unread,
Sep 22, 2015, 12:02:28 PM9/22/15
to ISO C++ Standard - Future Proposals
With the use of SIMD instructions alignment of data types is becoming increasingly important. The recent C++11 standard brought new tools for dealing with alignment (alignas(x), alignof(t) etc). However heap allocations are still required only to conform to the fundamental alignment of the platform. Meaning that alignas() attributes are ignored for operator new/delete and by extension make_shared/make_unique/vector etc which necessitates error-prone manual allocation of aligned memory (or writing a custom aligned_allocator and consistently using it everywhere).

As the standard provides tools for specifying alignment of types, I believe it would be desirable to provide a new "std::aligned_allocator<T, size_t alignment>" allocator type in the standard library. This allocator would produce aligned memory, for example boost provides such an allocator: http://www.boost.org/doc/libs/1_58_0/doc/html/align/tutorial.html#align.tutorial.aligned_allocator. Another implementation can be found here: https://gist.github.com/donny-dont/1471329 and there exists many more. This is a common problem.

If such an "aligned_allocator" would be available, then for example "std::make_shared" could be augmented to automatically allocate aligned memory, like so:

    template< typename T, std::size_t align = std::alignment_of<T>::value, typename... Args >
    std::shared_ptr<T> make_shared(Args&&... args){
        constexpr std::size_t default_alignment = ...; // Platform specific constant

        if (align > default_alignment) {
            typedef aligned_allocator<T, align> alloc_t;
            return std::allocate_shared<T, alloc_t>(alloc_t(), std::forward<Args>(args)...);
        }
        else {
            return std::make_shared<T>(std::forward<Args>(args)...);
        }
}

Note that the alignment is automatically determined and the syntax for calling make_shared will not change and this change will not break existing code. In a similar fashion make_unique could also be augmented.

Likewise for std::vector changing:
    template<class T, class Allocator = std::allocator<T>> class vector;
to
    template<class T, class Allocator = std::aligned_allocator<T, std::alignment_of<T>>> class vector;

would not break any existing code (*1,*2,*3) while allowing vector to respect the alignment of T. Similarly the other std containers can be augmented to respect the alignment of the contained types.

*1: Any well formed program that functions with the default allocator will also function with a stricter alignment requirement. Any bit hacks done on lower bits of the address will still work. Software in any way depending on particular properties of the default allocators returned addresses (other than fundamental alignment) has UB anyway.
*2: Any program that was buggy due to improper alignment will have been automatically fixed.
*3: Any program that has solved the problem already by using their own aligned allocator will not be affected as they are specifying the allocator explicitly.

Reply all
Reply to author
Forward
0 new messages