c++stack-overflowbad-alloc

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


I made a class that recursively creates itself using new (just for fun!), expecting that this will throw std::bad_alloc due to infinite dynamic allocation (heap overflow). But stack overflow happened instead of std::bad_alloc. Why does this happen?

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 asked what happens if I change new Overflow() to new Overflow[100000], and this gave me std::bad_alloc. According to the answers, shouldn't this also give me stack overflow?


Solution

  • I made a small modification to your code:

    #include <array>
    
    template <size_t size>
    class Overflow
    {
    private:
        Overflow* overflow;
        std::array<int,size> x;
    
    public:
        Overflow()
        {
            overflow = new Overflow();
        }
    };
    

    On wandbox this

    int main()
    {
        Overflow<1> overflow_happens;
    }
    

    results in a segmentation fault caused by overflow of the stack.

    However, this

    int main()
    {    
        Overflow<10000> bad_alloc;
    }
    

    results in

    terminate called after throwing an instance of 'std::bad_alloc'
      what():  std::bad_alloc
    
    Aborted
    

    You basically have two competing effects here. As a first approximation (details are a bit more involved) you have for each recursion of the consturctor:

    Hence whether you first get a stack overflow or bad_alloc depends on the size of Overflow. And for small sizes you'll first get a overflow, because stack space is much more limited than heap space.

    PS: I missed your edit... if you place new Overflow[100000] in the constructor in your code you amplify the required heap space, just as I did by adding the array member. On the stack you still have a single pointer and hence you run out of heap much earlier.