全局分配函数
要分配任意(无类型)内存块,可以使用全局分配函数(第 3.7.4/2 节);
void* operator new(std::size_t);
void* operator new[](std::size_t);
可用于执行此操作 (§3.7.4.1/2)。
§3.7.4.1/2
分配函数尝试分配请求的存储量。如果成功,它将返回存储块的起始地址,该存储块的长度(以字节为单位)应至少与请求的大小一样大。从分配函数返回时,分配的存储空间的内容没有任何限制。通过连续调用分配函数分配的存储的顺序、连续性和初始值是未指定的。返回的指针应适当对齐,以便它可以转换为具有基本对齐要求(3.11)的任何完整对象类型的指针,然后用于访问分配的存储中的对象或数组(直到存储被显式释放)调用相应的释放函数)。
3.11 是这样说的基本对齐要求;
§3.11/2
基本对齐由小于或等于所有上下文中实现支持的最大对齐的对齐表示,该对齐等于alignof(std::max_align_t)
.
只是为了确保分配函数的行为必须像这样;
§3.7.4/3
C++ 程序中定义的任何分配和/或释放函数(包括库中的默认版本)应符合 3.7.4.1 和 3.7.4.2 中指定的语义。
引述自C++ WD n4527 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4527.pdf.
假设 8 字节对齐小于平台的基本对齐(看起来确实如此,但这可以在目标平台上验证)static_assert(alignof(std::max_align_t) >= 8)
) - 您可以使用全局::operator new
来分配所需的内存。分配后,可以根据您的大小和对齐要求对内存进行分段和使用。
这里的另一种选择是 the std::aligned_storage http://en.cppreference.com/w/cpp/types/aligned_storage它能够为您提供符合任何要求的内存。
typename std::aligned_storage<sizeof(T), alignof(T)>::type buffer[100];
从问题中,我假设这里的大小和对齐方式T
将会是8。
最终内存块的示例如下(包括基本 RAII);
struct DataBlock {
const std::size_t element_count;
static constexpr std::size_t element_size = 8;
void * data = nullptr;
explicit DataBlock(size_t elements) : element_count(elements)
{
data = ::operator new(elements * element_size);
}
~DataBlock()
{
::operator delete(data);
}
DataBlock(DataBlock&) = delete; // no copy
DataBlock& operator=(DataBlock&) = delete; // no assign
// probably shouldn't move either
DataBlock(DataBlock&&) = delete;
DataBlock& operator=(DataBlock&&) = delete;
template <class T>
T* get_location(std::size_t index)
{
// https://stackoverflow.com/a/6449951/3747990
// C++ WD n4527 3.9.2/4
void* t = reinterpret_cast<void*>(reinterpret_cast<unsigned char*>(data) + index*element_size);
// 5.2.9/13
return static_cast<T*>(t);
// C++ WD n4527 5.2.10/7 would allow this to be condensed
//T* t = reinterpret_cast<T*>(reinterpret_cast<unsigned char*>(data) + index*element_size);
//return t;
}
};
// ....
DataBlock block(100);
我构建了更详细的示例DataBlock
有合适的模板construct
and get
功能等,现场演示在这里 http://coliru.stacked-crooked.com/a/37af4796160ecd8c and 这里进行进一步的错误检查等。 http://coliru.stacked-crooked.com/a/8b7251effad9b667.
关于别名的注释
看起来原始代码中确实存在一些别名问题(严格来说);您分配一种类型的内存并将其转换为另一种类型。
它可能会在您的目标平台上按您的预期工作,但您不能依赖它。我对此见过的最实际的评论是;
“未定义的行为会产生令人讨厌的结果,通常会做你认为应该做的事情,直到它不做为止” - hvd https://stackoverflow.com/questions/31204824/why-give-a-c-compiler-warning-when-returning-an-rvalue-reference#comment50412114_31204824.
您拥有的代码可能会起作用。我认为最好使用适当的全局分配函数,并确保在分配和使用所需内存时不存在未定义的行为。
别名仍然适用;一旦分配了内存,别名就适用于它的使用方式。一旦分配了任意内存块(如上面的全局分配函数)并且对象的生命周期开始(§3.8/1) - 别名规则适用。
关于什么std::allocator
?
虽然std::allocator http://en.cppreference.com/w/cpp/memory/allocator适用于同质数据容器,您正在寻找的内容类似于异构分配,标准库中的实现(给定分配器概念 http://en.cppreference.com/w/cpp/concept/Allocator)提供了有关原始内存分配和所需对象的相应构造的一些指导。