Когда класс динамически размещает себя в конструкторе, почему переполнение стека происходит вместо std :: 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. Согласно ответам, не должно ли это также привести к переполнению стека?

Ответ 1

Переполнение стека происходит из-за бесконечной рекурсии. Вызов Overflow() заставляет вас вызывать Overflow() снова, снова и снова. Эти вызовы функций должны идти в стек. Так как ваш стек меньше вашей кучи, вам не хватит места в стеке для всех этих вызовов конструктора, прежде чем вам не хватит памяти для всех объектов, которые вы создаете.

Ответ 2

Потому что вы рекурсивно вызываете конструктор, метод, многократно. Вызовы методов переносятся в стек вызовов. Поскольку размер стека намного меньше доступной кучи, стек вызовов переполняется до того, как куча заканчивается.

Ответ 3

Я сделал небольшую модификацию вашего кода:

#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;
}

приводит к ошибке сегментации, вызванной переполнением стека.

Тем не менее, это

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] в конструктор в вашем коде, вы увеличите требуемое пространство кучи, как я сделал, добавив элемент array. В стеке у вас все еще есть один указатель и, следовательно, вы исчерпали кучу намного раньше.