程序在大型数组初始化时终止

Program terminates in initialization of large array

本文关键字:终止 初始化 数组 大型 程序      更新时间:2023-10-16

我有 V = 3997962,我想有一个由 C++ 中的整数向量组成的该大小的数组。

当我像这样初始化它时:

const int V = 3997962;
vector<int> array[V];

程序终止时不提示任何错误。

是堆栈溢出错误吗?我该怎么做?

我应该这样定义它吗:

vector<int>* test = new vector<int>[V];

如何将此变量传递给函数?它应该如何定义为参数?我到底需要删除它吗?

如果这是一个局部变量,你基本上是在自动存储中要求近 800 万个指针变量。由于堆栈溢出,这可能会失败。

您可以改用向量的向量。

vector<vector<int>> array(V);

上面的结果是一个名为 array 的向量,该向量填充V默认初始化的 vector<int> s。

这很可能是堆栈溢出。

您正在分配V vector<int>。虽然这些向量的元素将在堆上分配,但向量本身(包含指针和一些其他对象)正在堆栈上分配。如果您有其中V,您可能会达到堆栈限制。

vector<int>* test = new vector<int>[V];

这是一种可能的解决方案,但并不理想。这将要求您稍后使用 delete[] test; delete[]数组。您可以通过将此动态分配的数组包装在更智能的指针中来解决此问题,但请继续阅读以获得更好的解决方案。

如何

将其传递给其他函数并不真正相关(您应该设计完全独立于客户端如何分配它们的函数参数),但您可以传递指针:

void f(vector<int>* param);
f(test);

也可以将参数写为vector<int> param[],这样可以更好地表达这个指针指向一个数组。 const也可以添加到您想要不变性的地方。但是,我们可以通过完全避免使用new和原始指针来找到更好的解决方案。

相反,我建议有一个vector<vector<int>>

vector<vector<int>> test(V);

现在,堆栈上实际上只有一个vector。该vector的元素本身vector,将在堆上分配,它们的元素也是如此。

您应该提供数组将具有静态存储持续时间。在某个名称空间中的任何函数外部定义它,如果要在函数中定义它,请使用关键字 static(例如 main)

static std::vector<int> array[V];

因为堆栈内存非常有限。

否则,请在堆中定义它或使用相同的向量。例如

std::vector<vector<int>> array( V );

std::vector<vector<int>> array;
array.reserve( V );

考虑到类std::vector具有成员函数max_size,该成员函数允许获取有关向量的最大可接受大小的信息。

如果

这是在某个函数的本地声明的,则您要求在自动存储空间中3997962 * sizeof(std::vector<int>)。为了更好地了解std::vector<int>的基本管理成员占用多少空间,请考虑:

#include <iostream>
#include <vector>
int main()
{
    std::cout << sizeof(std::vector<int>) << 'n';
}

输出(OSX 10.10,64 位叮当 3.5)

24

因此,(至少在我的平台上)您请求至少 3997962 * 24 或 95951088 字节(大约 92 MB)的自动存储。所以是的,你很可能会耗尽你的自动存储空间。要将单个向量的主要管理数据以外的所有管理数据放在堆上,您可以:

std::vector<std::vector<int>> vv(N);

这将创建一个Nint向量的向量,所有这些向量最初都是空的和堆管理的。 基本向量vv内部的核心管理数据仍在自动存储中,但如您所见:

#include <iostream>
#include <vector>
int main()
{
    std::cout << sizeof(std::vector<std::vector<int>>) << 'n';
}

输出

24

自动存储的占地面积大大减少

解决您的后续问题:

  • 如何将此变量传递给函数?
  • 它应该如何定义为参数?

如何传递这个(第一个问题)完全取决于你是否需要修改它的内容,并将影响你声明参数的方式(第二个问题)。为避免昂贵的副本,请通过引用传递它。其次,如果被调用方不需要修改数据,则按const传递数据:

// read-only, pass as const-reference
void doesnt_modify(const std::vector<std::vector<int>>& vv)
{
    // use here, can't modify
}
// writable, pass as reference
void can_modify(std::vector<std::vector<int>>& vv)
{
    // use here, can modify
}

当向量数据位于堆上时。矢量对象大小本身是(在 64 位,Linux 上)24 字节,因此您在堆栈上定位为 24*3997962 ~ 95MB。例如,Linux 机器上的默认堆栈限制为 ~8MB(尝试ulimit -a检查)。所以它很可能是一个流动的堆栈。