static_assert(sizeof(std::array<int,5>)==5*sizeof(int));
以上内容可以避免在 std::array 的末尾添加任何填充。到目前为止,没有主要编译器会导致上述失败,我敢打赌将来不会。
当且仅当上述失败时,std::vector<std::array<int,5>> v(2) 将在 std::arrays 之间产生“间隙”。
这并没有你想要的那么大的帮助;生成的指针如下:
int* ptr = &v[0][0];
只有一个有效域直到ptr+5,而取消引用ptr+5 是未定义的行为。
这是由于别名规则造成的;即使您知道它在那里,也不允许您“走”过一个对象的末端进入另一个对象,除非您首先往返于某些类型(如char*),其中允许较少限制的指针算术。
反过来,该规则的存在允许编译器推断通过哪个指针访问哪些数据,而无需证明任意指针运算可以让您访问外部对象。
所以:
struct bob {
int x,y,z;
};
bob b {1,2,3};
int* py = &b.y;
无论您如何将py 用作int*,您不能合法地修改x 或z。
*py = 77;
py[-1]=3;
std::cout << b.x;
编译器可以优化std::cout 行以简单地打印1,因为py[-1]=3 可能尝试修改b.x,但通过这种方式这样做是未定义的行为。
同样的限制阻止您从std::vector 中的第一个数组转到第二个数组(即,超出ptr+4)。
创建ptr+5 是合法的,但只能作为一个过去的指针。比较 ptr+5 == &v[1][0] 也没有在结果中指定,即使它们的二进制值在每个主要硬件系统上的每个编译器中绝对是相同的。
如果你想在兔子洞里走得更远,由于指针别名的这些限制,甚至不可能在 C++ 本身内实现std::vector<int>。最后我检查了(在c++17 之前,但我没有看到 C++17 中的解决方案)标准委员会正在努力解决这个问题,但我不知道任何此类努力的状态。 (这不是您想象的问题,因为没有什么要求std::vector<int> 在符合标准的 C++ 中实现;它必须简单地具有标准定义的行为。它可以在内部使用特定于编译器的扩展。)