使用 std::vector>作为 T 的平面连续数组
std::vector
将其元素连续存储在内存中。 std::array
只是 N
个连续 T
元素的包装,直接存储在对象本身中。
因此我想知道大小为 n
的 std::vector
是否也可以被视为 数组T
大小为 N*n
。
考虑以下代码(也此处):
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
替换为结构:
struct S {
int i,j,k;
};
std::vector<S> v(10);
S* s_ptr = v.data();
int* i_ptr = &S.i;
它的工作原理是否相同?
不会触发未定义行为的替代方案是什么?
上下文:我有一个 std::vector
并且我想序列化它以通过网络发送它。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不,但是是的。
不可以,C++ 标准不允许您将包含数组的结构体,甚至包含统一元素的结构体,打包在一起作为基本类型的单个连续的较大数组。
是的,世界上足够多的生产代码要求它工作,没有编译器会很快阻止它工作。
需要注意的事项包括包装。添加静态断言,表明结构和数组的大小符合您的预期。另外,避免过分关注对象的生命周期或从第一个索引之外的索引“向后”;如果你做了一些奇怪的事情,C++ 的可达性规则更容易让你受到影响。
另一个担忧是,这些构造正在接受积极的调查。例如,std 向量无法在标准 C++ 或
std::launder
和bit_cast
中实现的惨败。当开发出一种真正的标准方法来做你想做的事情时,切换到它可能是一个好主意,因为旧的技术将变得不太可能得到支持。No, but yes.
No, the C++ standard does not let you treat structs with arrays in them, or even structs with uniform elements, packed together as a single contiguous larger array of the base type.
Yes, in that enough in world production code requires this to work that no compiler is going to break it from working any time soon.
Things to watch out for include packing. Add static asserts that the size of the structs and arrays is what you expect. Also, avoid being fancy with object lifetime or going "backwards" from an index besides the first one; the reachability rules of C++ are slightly more likrly to bite you if you do strange things.
Another concern is that these constructs are under somewhat active investigation; the fiasco that std vector cannot be implemented in standard C++, for example, or
std::launder
andbit_cast
. When a real standard way to do what you want develops, switching to it might be a good idea, because the old technique will become less likely to be supported.从纯粹迂腐的角度来看,从
i
等于3
的迭代开始,代码具有未定义的行为:i_ptr + 3
点v
的第一个元素中的一个过去的数组,因此不允许您取消引用它。除此之外的指针算术,即
i_ptr + 4
,具有未定义的行为,因为指针算术只允许在数组内部和数组的后一位。v
不同元素组成的int
数组不会形成更大的int
组合数组。他们不能被这样对待。即使
std::array
的大小与int[3]
相同并且因此除了数组之外没有其他填充或成员,上述内容也成立。对于
struct
版本,在取消引用i_ptr + 1
(v[0].i 的前一对象指针)时,已发生未定义的行为
。From a purely pedantic point-of-view, the code has undefined behavior starting with the iteration with
i
equal to3
:i_ptr + 3
points one-past-the-array in the first element ofv
and so you are not allowed to dereference it.Pointer arithmetic beyond that, i.e.
i_ptr + 4
, has undefined behavior because pointer arithmetic is only allowed inside an array and one-past-the-array.The
int
arrays of different elements ofv
do not form a larger combined array ofint
s. They cannot be treated as such.The above holds even if
std::array
has the same size asint[3]
and therefore has no other padding or members aside from the array.In case of the
struct
version, undefined behavior occurs already when dereferencingi_ptr + 1
, the one-past-the-object pointer ofv[0].i
.