我经常需要将动态数组的开头与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
。
除此之外,你觉得这有什么问题吗?是否存在一种不易出错的替代方案,但在完成分配后对用户完全透明?
答案 0 :(得分: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};
}
这样,没有客户端可以将原始指针放入不合适的智能指针中,因为它们从不首先得到原始指针。并且你可以防止内存泄漏意外地将原始指针放在一个聪明的指针中。
正如@KonradRudolph指出的那样,标准本身就是这样 - 在C ++ 14中,std::make_unique
正是普通new
的包装。