对齐的动态数组和智能指针

Aligned dynamic array and smart pointer

我经常需要将动态数组的开头与 16、32 或 64 字节的边界对齐以进行矢量化,例如 SSE、AVX、AVX-512。我正在寻找一种透明且安全的方式将其与智能指针结合使用,特别是 std::unique_ptr.

给定分配和释放例程的实现,比如说

template<class T>
T * allocate_aligned(int alignment, int length)
{
    // omitted: check minimum alignment, check error
    T * raw = 0;
    // using posix_memalign as an example, could be made platform dependent...
    int error = posix_memalign((void **)&raw, alignment, sizeof(T)*length);
    return raw;
}

template<class T>
struct DeleteAligned
{
    void operator()(T * data) const
    {
        free(data);
    }
};

我想做这样的事情

std::unique_ptr<float[]> data(allocate_aligned<float>(alignment, length));

但我不知道如何在不要求用户指定的情况下让 unique_ptr 使用正确的 Deleter(这是错误的潜在原因)。我找到的替代方法是使用模板别名

template<class T>
using aligned_unique_ptr = std::unique_ptr<T[], DeleteAligned<T>>;

然后我们可以使用

aligned_unique_ptr<float> data(allocate_aligned<float>(alignment, length));

剩下的问题是没有什么可以阻止用户将原始指针放入 std::unique_ptr

除此之外,你觉得这有什么问题吗?有没有一种更不容易出错,但在分配完成后对用户完全透明的替代方案?

你永远不应该 return 拥有原始指针。 allocate_aligned 违反了这一点。改为 return 适当的智能指针:

template<class T>
std::unique_ptr<T[], DeleteAligned<T>> allocate_aligned(int alignment, int length)
{
    // omitted: check minimum alignment, check error
    T * raw = 0;
    // using posix_memalign as an example, could be made platform dependent...
    int error = posix_memalign((void **)&raw, alignment, sizeof(T)*length);
    return std::unique_ptr<T[], DeleteAligned<T>>{raw};
}

这样,任何客户端都无法将原始指针放入不合适的智能指针中,因为他们从一开始就无法获得原始指针。并且您可以防止内存泄漏,因为意外地根本没有将原始指针放在智能指针中。

正如@KonradRudolph 指出的那样,标准本身就是这样发展的——在 C++14 中,std::make_unique 正是普通 new.

的包装器