当类在构造函数中动态分配自身时,为什么会发生堆栈溢出而不是std :: bad_alloc?

时间:2019-06-11 13:59:12

标签: c++ stack-overflow bad-alloc

我制作了一个使用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。根据答案,这不应该还会给我带来堆栈溢出吗?

3 个答案:

答案 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 }}成员。在堆栈上,您仍然只有一个指针,因此很早就用完了堆。