程序在大型数组初始化时终止
Program terminates in initialization of large array
我有 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);
这将创建一个N
个int
向量的向量,所有这些向量最初都是空的和堆管理的。 基本向量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
检查)。所以它很可能是一个流动的堆栈。
- 是否可以初始化不可复制类型的成员变量(或基类)
- C++使用整数的压缩数组初始化对象
- C++初始化基类
- 多成员Constexpr结构初始化
- 复制列表初始化的隐式转换的等级是多少
- 内联映射初始化的动态atexit析构函数崩溃
- 如何在C++中初始化嵌套类中的2个memeber
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 没有用于初始化C++中的变量模板的匹配构造函数
- 在未初始化映射的情况下,将值插入到映射的映射中
- C++成员初始化
- 为什么在C++中首先初始化成员类
- 同时具有"聚合初始化"和"模板推导"
- 初始化具有非默认构造函数的std::数组项的更好方法
- 以这种方式初始化的 char 数组是否会自动添加空终止符?
- 初始化和终止Qt应用程序的正确方法?
- 如果初始化或销毁因未处理的异常而终止,则必须销毁完全构造的子对象
- 程序在大型数组初始化时终止
- 初始化失败时如何终止qt编程
- 初始化char数组以容纳非null终止的字符串