考虑一个班级:
template <typename T>
struct A{
//...many public member functions...
T x;
T y;
T z;
}
另一个,类似的:
template <typename T>
struct B{
//many public member functions
T x;
T y;
}
虽然此处未指定,T
将始终为float
或int
或bool
。
现在考虑另一个结构:
struct Pair{
A<float> a;
B<float> b;
}
现在是vector
:
std::vector<Pair> bigBunch;
假设x
中的所有y
,z
,bigBunch
都是连续的,有多安全?我知道vector
保证Pair
之间的连续内存,但我也知道struct
不一定能保证连续的内存,因为填充可能发生。但是,如果您的struct
元素属于不同类型,我认为填充只会带来风险。
我希望能够获得指向bigBunch[0].a.x
的指针,然后知道在float
的整个内容中我可以期待bigBunch
的连续流。实际上,指向bigBunch[0].a.x
的指针指向与`bigBunch[0].a
相同的位置。
如果Pair.a
和Pair.b
是相同或不同的类型,例如混合int
和float
而不是两者是同一类型({{ 1}}在这个例子中)?
答案 0 :(得分:1)
但是,如果你的struct元素是不同的类型,我认为填充只是一种风险。
这不太准确,主要与内存中所占空间有多大关系。
您的示例使用float
,这是4个字节,因此不会导致填充。填充的整个目的是加速内存访问,4字节边界上的4字节对象都可以。
因此,您应该可以假设自己拥有float
的流,但如果Pair
bool
上有b
,则可能不会。我这样说的原因是因为它可能决定{{1}}在4字节边界上最好用,这会引入一个填充字节。
答案 1 :(得分:1)
AFAIK,标准中没有任何内容阻止编译器添加填充,如果它认为这是一个好主意。编译器在这件事上确实有很大的余地。这意味着最好的做法是防御并明确指示编译器打包数据,即使例如4字节边界上的4字节浮点不应导致填充。
我的另一个建议是使用static_assert
来验证所需的大小。例如,
template <typename T>
struct A{
//...many public member functions...
T x;
T y;
T z;
} __attribute__ ((__packed__));
static_assert(sizeof(A) == 3*sizeof(T), "struct A shouldn't be padded");
如果您没有C ++ 11,则可以使用BOOST_STATIC_ASSERT
代替。编辑:struct的右括号之后的__attribute__ ((__packed__))
位是GCC特定的确保紧密压缩结构的方法。
您应该考虑的另一件事是,如果您能够将vector<Pair>
视为一个没有间隙的大float
数组,那么您真正获益。据我所知,如果必须迭代所有内容,或者必须将数据传递给需要连续数据的其他库,可能会使某些算法更方便编写。但是我猜你正在用这些结构进行大量的数学计算,你的编译器可能能够自动向量化一些结构,例如,如果struct A
是128位对齐的话,可以使用SSE。在我的答案的这一部分中,我有很多猜测,所以如果它不适用于你,请忽略它。
PS:你的结构的右大括号后不要忘记分号。
答案 2 :(得分:1)
假设bigBunch中的所有x,y,z是多么安全 连续?
不安全。编译器可以自由填充。取决于T
指向bigBunch [0] .a.x的指针会指向同一个地方 说'bigBunch [0] .a。
这是安全的假设。
如果Pair.a和Pair.b是相同或不同的类型,这是否重要, 例如混合整数和浮动而不是两者都是同一类型 (在这个例子中浮动)?
假设是不安全的。对于int
和float
,我们可能会很幸运,但可能不是short
和int
填充故事在32位计算机和64位计算机之间切换。如果您希望代码适用于所有体系结构,则无法对填充和对齐进行假设。
有关一般性讨论,请参阅http://en.wikipedia.org/wiki/Data_structure_alignment
总之,在程序中永远不要假设填充: - )