【发布时间】:2020-09-29 21:32:27
【问题描述】:
我想为几种不同类型的连续数组分配内存。也就是说,像这样,但具有动态大小:
template <typename T0, std::size_t N0, typename T1, std::size_t N1, ...>
struct {
T0 t0s[N0];
T1 t1s[N1];
...
};
天真地,大小只是sizeof(T0) * N0 + sizeof(T1) * N1 + ...,但我认为对齐让它变得很棘手。您将在alignof(T0) 上对齐整个内容,然后在N0 T0s 之后,您必须找出alignof(T1) 点才能启动T1s。这有std::align,但它是为了在你已经分配了内存之后找到放置它们的位置,所以在分配内存之前使用它需要一点努力。
有没有一些简单的现成方法来计算像这样的动态结构的大小和偏移量?我正在描绘一个类似的函数
// Return the offsets in bytes of the ends of each array
template <typename... Ts>
std::array<std::size_t, sizeof...(Ts)>
calculateOffsets(const std::array<std::size_t, sizeof...(Ts)> sizes);
例如:
auto offsets = calculateOffets<char, float>({3, 2});
// Offsets is now {4, 12} because the layout is [cccXffffFFFF] where c is a char, X is padding, f and F are the two floats.
// Now we can allocate a buffer of size offsets.back() with alignment alignof(char) and placement-new 3 chars starting at buf + 0, and 2 floats at buf + offsets.front()
这很有趣,因为编译器显然内置了这个逻辑,因为在编译时它知道上面结构的布局,而大小是静态的。
(到目前为止,我只对 POD 类型感兴趣;要完全通用,我还需要处理异常安全的构造和销毁。)
【问题讨论】:
-
std::offsetof但我不确定您将如何使用它,因为您需要知道所有班级成员的姓名。我想你可以切换到拥有一个std::tuple数组而不是单个成员数组,以使这更容易。 -
如果您的数组在大小上是“动态的”,那么更现实的说明是该结构将包含指向每个连续序列的多个指针吗?如果是这样,您总是可以分配所有类型的最高对齐,然后通过减少对齐大小来分配指针。这将利用在 16 字节边界对齐的对象也以 8 字节边界对齐的事实,等等
-
您没有提供该问题的背景信息 - 因此,就我们所知,这可能是一个 X/Y 问题 - 您真正想解决什么问题?您可以在编译时使用模板等构建各种表格,然后使用循环从那里推断对齐方式,这只是一个想法。或者您可以切换设计并使用适合目标机器的通用对齐方式 - 然后手动将您的东西对齐到一些未对齐的内存上。
-
同样,仅仅因为编译器已经构建了这个逻辑,并不意味着它应该被公开,甚至不意味着这样做很简单。
-
我没有需要解决的特定问题,我只是惊讶地发现编译器可以轻松完成的事情似乎没有库相等的。我希望避免两个分配但有连续的内存(即,我可以分配一个
std::pair<T0, T1>s 的缓冲区),但随后迭代T0s 并非易事。