在这种情况下,我可以依赖连续的内存吗?

时间:2013-04-04 03:55:43

标签: c++

考虑一个班级:

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将始终为floatintbool

现在考虑另一个结构:

struct Pair{
  A<float> a;
  B<float> b;
 }

现在是vector

 std::vector<Pair> bigBunch;

假设x中的所有yzbigBunch都是连续的,有多安全?我知道vector保证Pair之间的连续内存,但我也知道struct不一定能保证连续的内存,因为填充可能发生。但是,如果您的struct元素属于不同类型,我认为填充只会带来风险。

我希望能够获得指向bigBunch[0].a.x的指针,然后知道在float的整个内容中我可以期待bigBunch的连续流。实际上,指向bigBunch[0].a.x的指针指向与`bigBunch[0].a相同的位置。

如果Pair.aPair.b是相同或不同的类型,例如混合intfloat而不是两者是同一类型({{ 1}}在这个例子中)?

3 个答案:

答案 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是相同或不同的类型,这是否重要,   例如混合整数和浮动而不是两者都是同一类型   (在这个例子中浮动)?

假设是不安全的。对于intfloat,我们可能会很幸运,但可能不是shortint

的情况

填充故事在32位计算机和64位计算机之间切换。如果您希望代码适用于所有体系结构,则无法对填充和对齐进行假设。

有关一般性讨论,请参阅http://en.wikipedia.org/wiki/Data_structure_alignment

总之,在程序中永远不要假设填充: - )