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

When a class dynamically allocates itself at constructor, why does stack overflow happen instead of std::bad_alloc?

我做了一个 class,它使用 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 问如果我将 new Overflow() 更改为 new Overflow[100000] 会发生什么,这给了我 std::bad_alloc。根据答案,这不应该也让我堆栈溢出吗?

因为你在递归地重复调用构造函数,一个方法。方法调用被推送到调用堆栈。由于堆栈大小远小于可用堆,因此调用堆栈会在堆用完之前溢出。

发生堆栈溢出是因为您有无限递归。调用 Overflow() 会使您一次又一次地调用 Overflow()。这些函数调用需要进入堆栈。由于您的堆栈小于您的堆,因此在您 运行 您正在创建的所有对象内存不足之前,所有这些构造函数调用都会 运行 内存不足 space。

我对你的代码做了一点小修改:

#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 的大小。对于小尺寸,您首先会溢出,因为堆栈 space 比堆 space.

更受限制

PS: 我错过了你的编辑...如果你将 new Overflow[100000] 放在代码的构造函数中,你会放大所需的堆 space,就像我添加 array 成员一样。在堆栈上,您仍然只有一个指针,因此您 运行 更早地离开堆。