对齐的动态数组和智能指针
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
.
的包装器
我经常需要将动态数组的开头与 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
.