4
\$\begingroup\$

I'm writing a program which uses OpenCL, and the OpenCL types are mostly over-aligned. Sometimes when using stl containers with these types, I'd get segfaults, so I tried to write my own aligned allocator which I could use instead of the standard allocator.

I've done a bit of testing in valgrind etc. and so far everything looks OK, but I don't know whether I might have written something which will bite me in the future. I'm especially worried about some reinterpret_casts in my allocate and deallocate methods.

Any feedback appreciated.

Here's the code:

namespace mem {

template <typename T, std::size_t N = alignof(T)>
class aligned_allocator {
    //  helper type with the alignment we want
    using aligned_type = std::aligned_storage_t<sizeof(T), N>;

public:
    //  type to allocate
    using value_type = T;

    //  ensure basic special class methods are enabled
    aligned_allocator()                                         = default;
    aligned_allocator(const aligned_allocator&)                 = default;
    aligned_allocator& operator=(const aligned_allocator&)      = default;
    aligned_allocator(aligned_allocator&&) noexcept             = default;
    aligned_allocator& operator=(aligned_allocator&&) noexcept  = default;

    //  allow construction from an allocator for another type
    //  (with the same alignment)
    template <typename U>
    aligned_allocator(const aligned_allocator<U>&) {}

    //  implementations may derive from the allocator polymorphically
    virtual ~aligned_allocator() noexcept = default;

    //  rebinding the allocator for another type should respect the alignment
    //  of that other type
    template <typename U>
    struct rebind {
        using other = aligned_allocator<U>;
    };

    //  allocate a type that we know will have the correct alignment
    //  then reinterpret the pointer
    T* allocate(std::size_t n) {
        return reinterpret_cast<T*>(new aligned_type[n]);
    }

    //  deallocate previously allocated memory
    void deallocate(T* p, std::size_t) {  //  don't care about size here
        delete[] reinterpret_cast<aligned_type*>(p);
    }
};

template <typename T, typename U, std::size_t N>
constexpr bool operator==(const aligned_allocator<T, N>&,
                          const aligned_allocator<U, N>&) {
    return true;
}

template <typename T, typename U, std::size_t N>
constexpr bool operator!=(const aligned_allocator<T, N>&,
                          const aligned_allocator<U, N>&) {
    return false;
}

}  //  namespace mem
\$\endgroup\$
  • \$\begingroup\$ Welcome to Code Review, nice question. Have you checked it for performance? \$\endgroup\$ – pacmaninbw Jul 20 '16 at 18:04
  • \$\begingroup\$ Thanks! No, I haven't run performance tests. \$\endgroup\$ – Reuben Thomas Jul 20 '16 at 19:34
  • \$\begingroup\$ Yes, you're right. I've removed the answer. \$\endgroup\$ – user2296177 Jul 20 '16 at 20:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.