对齐动态数组和智能指针

Sim*_*mon 12 c++ memory-alignment unique-ptr c++11

我经常需要将动态数组的开头与用于矢量化的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);
    }
};
Run Code Online (Sandbox Code Playgroud)

我想做这样的事情

std::unique_ptr<float[]> data(allocate_aligned<float>(alignment, length));
Run Code Online (Sandbox Code Playgroud)

但我无法弄清楚如何unique_ptr使用正确Deleter而无需用户指定它(这是导致错误的潜在原因).我找到的替代方法是使用模板别名

template<class T>
using aligned_unique_ptr = std::unique_ptr<T[], DeleteAligned<T>>;
Run Code Online (Sandbox Code Playgroud)

然后我们可以使用

aligned_unique_ptr<float> data(allocate_aligned<float>(alignment, length));
Run Code Online (Sandbox Code Playgroud)

剩下的问题是没有任何东西阻止用户将原始指针放入std::unique_ptr.

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

Rei*_*ica 10

你永远不应该返回拥有原始指针.allocate_aligned违反了这一点.更改它以返回相应的智能指针:

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};
}
Run Code Online (Sandbox Code Playgroud)

这样,没有客户端可以将原始指针放入不合适的智能指针中,因为它们从不首先获得原始指针.并且您可以防止内存泄漏意外地将原始指针放在智能指针中.

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

  • 值得一提的是,这基本上是`std :: make_unique`在C++ 14中为`new`做的事情. (2认同)