使用 std::vector>作为 T 的平面连续数组

发布于 2025-01-09 01:51:48 字数 1331 浏览 2 评论 0 原文

std::vector 将其元素连续存储在内存中。 std::array 只是 N 个连续 T 元素的包装,直接存储在对象本身中。

因此我想知道大小为 nstd::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> 并且我想序列化它以通过网络发送它。

A std::vector stores its elements contiguously in memory. An std::array<T,N> is just a wrapper around N contiguous T elements, stored directly in the object itself.

Hence I am wondering if a std::vector<std::array<T,N>> of size n can also be seen as an array of T of size N*n.

Consider the following code (also here):

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;
}

It appears to work for my setup, but is the code legit or is it undefined behavior?

If I were to replace std::array<int,3> with a struct:

    struct S { 
        int i,j,k;
    };

    std::vector<S> v(10);
    S* s_ptr = v.data();
    int* i_ptr = &S.i;

Would it work the same?

What would be the alternatives that would not trigger undefined behavior?

Context: I have a std::vector<std::array<int,3>> and I want to serialize it to send it over a network.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

腹黑女流氓 2025-01-16 01:51:48

不,但是是的。

不可以,C++ 标准不允许您将包含数组的结构体,甚至包含统一元素的结构体,打包在一起作为基本类型的单个连续的较大数组。

是的,世界上足够多的生产代码要求它工作,没有编译器会很快阻止它工作。

需要注意的事项包括包装。添加静态断言,表明结构和数组的大小符合您的预期。另外,避免过分关注对象的生命周期或从第一个索引之外的索引“向后”;如果你做了一些奇怪的事情,C++ 的可达性规则更容易让你受到影响。

另一个担忧是,这些构造正在接受积极的调查。例如,std 向量无法在标准 C++ 或 std::launderbit_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 and bit_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.

傲娇萝莉攻 2025-01-16 01:51:48

从纯粹迂腐的角度来看,从 i 等于 3 的迭代开始,代码具有未定义的行为:

i_ptr + 3v 的第一个元素中的一个过去的数组,因此不允许您取消引用它。

除此之外的指针算术,即i_ptr + 4,具有未定义的行为,因为指针算术只允许在数组内部和数组的后一位。

v 不同元素组成的 int 数组不会形成更大的 int 组合数组。他们不能被这样对待。

即使 std::array 的大小与 int[3] 相同并且因此除了数组之外没有其他填充或成员,上述内容也成立。


对于 struct 版本,在取消引用 i_ptr + 1v[0].i 的前一对象指针)时,已发生未定义的行为

From a purely pedantic point-of-view, the code has undefined behavior starting with the iteration with i equal to 3:

i_ptr + 3 points one-past-the-array in the first element of v 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 of v do not form a larger combined array of ints. They cannot be treated as such.

The above holds even if std::array has the same size as int[3] and therefore has no other padding or members aside from the array.


In case of the struct version, undefined behavior occurs already when dereferencing i_ptr + 1, the one-past-the-object pointer of v[0].i.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文