std::vector
将其元素连续存储在内存中。std::array<T,N>
只是围绕N
连续T
元素的包装器,直接存储在对象本身中。
因此,我想知道大小n
的std::vector<std::array<T,N>>
是否也可以被视为大小N*n
的T
数组。
请考虑以下代码(也在此处):
int main() {
// init a vector of 10 arrays of 3 elements each
std::vector<std::array<int,3>> v(10);
// fill it
for (int i=0; i<10; ++i) {
v[i] = {3*i,3*i+1,3*i+2};
}
// take the first array
std::array<int,3>* a_ptr = v.data();
// take the first element of the array
int* i_ptr = a_ptr->data();
// dereference the pointer for 3*10 elements
for (int i=0; i<30; ++i) {
std::cout << i_ptr[i] << ',';
}
return 0;
}
它似乎适用于我的设置,但代码是合法的还是未定义的行为?
如果我用结构体替换std::array<int,3>
:
struct S {
int i,j,k;
};
std::vector<S> v(10);
S* s_ptr = v.data();
int* i_ptr = &S.i;
它会一样工作吗?
不会触发未定义行为的替代方案是什么?
上下文:我有一个std::vector<std::array<int,3>>
,我想对其进行序列化以通过网络发送。
不,但是是的。
不,C++ 标准不允许您将包含数组的结构,甚至不允许将具有统一元素的结构打包为基类型的单个连续较大数组。
是的,在世界生产代码中,足够多的代码需要它才能工作,没有编译器会很快中断它的工作。
需要注意的事项包括打包。 添加静态断言结构和数组的大小是您所期望的。 此外,避免花哨的对象生存期或从第一个索引以外的索引"倒退";C++的可达性规则在你做奇怪的事情时更容易咬你。
另一个问题是,这些结构正在接受一些积极的调查;例如,性病载体无法在标准C++或std::launder
和bit_cast
中实现的惨败。 当开发一种真正的标准方法来做你想做的事情时,切换到它可能是一个好主意,因为旧技术将变得不太可能得到支持。
从纯粹迂腐的角度来看,代码具有未定义的行为,从迭代开始,i
等于3
:
i_ptr + 3
在v
的第一个元素中指向一个过去的数组,因此不允许取消引用它。
指针算术超出此范围,即i_ptr + 4
具有未定义的行为,因为指针算术只允许在数组内和数组中通过。
v
的不同元素的int
数组不会形成更大的int
数组。他们不能被这样对待。
即使std::array
与int[3]
具有相同的大小,因此除了数组之外没有其他填充或成员,上述情况也成立。
在struct
版本中,在取消引用i_ptr + 1
(v[0].i
的过去对象指针)时已经发生了未定义的行为。