我制作了一个使用new
递归创建自己的类(只是为了好玩!),期望由于无限的动态分配(堆溢出)而将抛出std::bad_alloc
。但是发生了堆栈溢出,而不是std::bad_alloc
。为什么会这样?
class Overflow
{
private:
Overflow* overflow;
public:
Overflow()
{
overflow = new Overflow();
}
};
int main()
{
Overflow overflow_happens; // stack overflow happens instead of std::bad_alloc exeption
}
@Caleth询问如果我将新的Overflow()更改为新的Overflow [100000],会发生什么,这给了我std::bad_alloc
。根据答案,这不应该还会给我带来堆栈溢出吗?
答案 0 :(得分:18)
由于无限递归,正在发生堆栈溢出。呼叫Overflow()
使您一次又一次地呼叫Overflow()
。这些函数调用需要进入堆栈。由于堆栈小于堆,因此所有构造函数调用都将耗尽堆栈空间,然后为所有正在创建的对象耗尽内存。
答案 1 :(得分:4)
因为您要递归地反复调用构造函数,方法。方法调用被推送到调用堆栈。由于堆栈大小比可用堆小得多,因此调用堆栈会在堆用完之前溢出。
答案 2 :(得分:1)
我对您的代码做了小修改:
#include <array>
template <size_t size>
class Overflow
{
private:
Overflow* overflow;
std::array<int,size> x;
public:
Overflow()
{
overflow = new Overflow();
}
};
在wandbox上
int main()
{
Overflow<1> overflow_happens;
}
导致由堆栈溢出引起的分段错误。
但是,this
int main()
{
Overflow<10000> bad_alloc;
}
结果
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted
基本上,您在这里有两个相互竞争的效果。作为构造函数的每次递归的第一个近似值(涉及更多细节):
Overflow*
Overflow
实例因此,究竟是首先出现堆栈溢出还是bad_alloc
,取决于Overflow
的大小。对于小尺寸,您首先会溢出,因为堆栈空间比堆空间受限制得多。
PS::我错过了您的编辑……如果您将new Overflow[100000]
放在代码的构造函数中,则会放大所需的堆空间,就像我添加{{1 }}成员。在堆栈上,您仍然只有一个指针,因此很早就用完了堆。