【问题标题】:Memory layout of C++ vector of structs结构体的 C++ 向量的内存布局
【发布时间】:2023-03-27 12:50:01
【问题描述】:

假设我有一个结构

struct Point
{
    int x;
    int y;
    int z;
};
Point p = {1,2,3};

我知道在内存中它是连续组织的

p = | 1 | 2 | 3 |

如果我有Point 结构中的std::vectordata() 函数是否也连续返回数组?或者是否还有额外的“东西”投入其中?例如

Point p1 = {1,2,3};
Point p2 = {4,5,6};
Point p3 = {7,8,9};
std::vector<Point> points;
points.push_back(p1);
points.push_back(p2);
points.push_back(p3);

调用points.data() 会返回指向如下数组的指针:

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8| 9 |
 ^ptr

此外,如果结构稍微复杂一点,包含一个向量,假设

MultiDimPoint
{
    std::vector<int> values;
}

这些MultiDimPoints 中的vector 是否也是连续的?也就是说,会

MultiDimPoint mdp1;
mdp1.values = std::vector<int>(0,1,2,3);

MultiDimPoint mdp2;
mdp2.values = std::vector<int>(4,5,6,7,8,9);

std::vector<MultiDimPoint> mdp_vec;
mdp_vec.pushback(mdp1);
mdp_vec.pushback(mdp2);

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8| 9 |
 ^ptr

mdp_vec.data() 何时被调用?

【问题讨论】:

  • 内存布局与此类结构的数组没有什么不同(因为在内部就是这样)。可以通过data() 成员函数访问内部数组,该函数返回指向数组的原始指针。

标签: c++ memory vector struct


【解决方案1】:

C++ 标准让每个 C++ 实现来定义和使用特定实现所需的任何结构填充。

您的 C++ 编译器可能会为此结构添加一些填充,以用于硬件驱动的对齐目的,这将导致向量中此 struct 的实例之间出现一些“间隙”。

话虽如此,对于仅包含纯 ints 的类,您不太可能在现代 C++ 实现中遇到这种填充。您可以通过观察此 struct 中的 sizeof 与单个 int 中的 sizeof 来确定您的 C++ 实现是否属于这种情况。

但是,如果您的目标是编写可在任何 C++ 实现上正常工作的可移植代码,则不应做出任何假设。

现在,当你有一个向量作为另一个类的成员,以及这些类的一个向量时,每个类成员中的每个向量都是完全相互独立的,你不能保证连续类成员中的向量会结束up 在一个连续的内存块中。事实上,你几乎可以保证他们不会。

【讨论】:

    【解决方案2】:

    要求std::vector 将元素打包成一个线性数组。但是,sizeof(Point) 的大小可能不是int 的三倍。它可能会被四舍五入到适合您的编译器的大小。通常有 pragma 来控制结构填充。

    每个向量都分配自己的内存,因此在MultiDimPoint 的情况下,它们很可能不会是连续的。如果他们是,那将是一个巧合。此外,C 运行时堆管理可能会在您请求的缓冲区之前和/或之后放置额外的数据。

    【讨论】:

      猜你喜欢
      • 2011-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-30
      • 1970-01-01
      • 2013-08-14
      相关资源
      最近更新 更多