Мне часто нужно выровнять начало динамического массива с границей 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));
но я не мог понять, как сделать get 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
.
Кроме того, вы видите что-то не так с этим? Есть ли альтернатива, которая менее подвержена ошибкам, но полностью прозрачна для пользователя после того, как было выполнено распределение?