Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: terminate called after throwing an instance of 'std::bad_alloc'

I am implementing a doubly linked list class of sorts which stores 'buckets' (the nodes), which each contain a predefined number of characters. Each bucket stores a pointer to the next and previous bucket, and the list class (BucketString) stores a pointer to the head Bucket. I am compiling using g++ which throws the error

terminate called after throwing an instance of 'std::bad_alloc'
  what(): std::bad_alloc
make: *** [run] Aborted (core dumped)

whenever I run the code and add a string of characters to the list, using the following add method, which is contained within my bucket class, and is called from the list class's own methods whenever needed.

Code:

std::size_t bucketSizeB;
int filled;
char* str;
Bucket* next;
Bucket* prev;

Bucket::Bucket() : bucketSizeB(7), str(new char[7]), next(NULL), prev(NULL), filled(0)
{}

Bucket::Bucket(std::size_t bucketSizeB_) : bucketSizeB(bucketSizeB_), str(new char[bucketSizeB]), next(NULL), prev (NULL), filled(0)
{}

Bucket::Bucket(const Bucket& rhs) : bucketSizeB(rhs.bucketSizeB), next(rhs.next), prev(rhs.prev), filled(rhs.filled)
{
    for (int i = 0 ; i < (int) bucketSizeB ; i++)
    {
        str[i] = rhs.str[i];
    }
}

void Bucket::add(std::string line)
{

    int diff = bucketSizeB - filled;    //if the bucket is already partially filled


    std::string tmp = line.substr(0, diff);

    for (std::size_t i = 0 ; i < tmp.length() ; i++)
    {

        str[filled] = line[i];
        ++filled;
    }

    if (line.length() > bucketSizeB)
    {

        next = new Bucket(bucketSizeB);

        next->prev = this;
        next->add(line.substr(diff, line.length()-diff));
    }
}
Bucket::~Bucket()
{
    if (prev)
    {
        if (next)
        {
            prev->next = next;
        }
        else
        {
            prev->next = NULL;
        }
    }
    if (next)
    {
        if (prev)
        {
            next->prev = prev;
        }
        else
        {
            next->prev = NULL;
        }
    }
    delete [] Bucket::str;
}

When the error is thrown, the add method is being called from the 'list' class member method append, which works as follows:

void BucketString::append (std::string& line)
{
    length += line.length();    //Just a way to store the length of the string stored in this BucketString object

    if (!head)   //If the head node pointer is currently null, create a new head pointer
    {

        head = new Bucket(bucketSize);
    }

    Bucket* tmp = head;

    while (tmp->next)   //Finds the tail node
    {
        tmp = tmp->next;
    }
    tmp->add(line);   //Calls the Bucket add function on the tail node
}

The header file for the bucket class is:

#include <cstddef>
#include <string>
#include <iostream>

#ifndef BUCKET_H_
#define BUCKET_H_

namespace RBNWES001
{
class Bucket
{

    public:
        //Special members and overloaded constructor
        Bucket(void);
        Bucket(std::size_t);
        Bucket(const Bucket&);
        ~Bucket();
        //Copy Assignment not included because it's not needed, I'm the only one who is gonna use this code! :)

        //Add method
        void add(std::string);

        int filled;
        char* str;
        Bucket* next;
        Bucket* prev;
        std::size_t bucketSizeB;
};
}

#endif
like image 801
wesrobin Avatar asked Mar 27 '13 23:03

wesrobin


2 Answers

1) You can prevent termination with a try/catch block.

2) It sounds like this is occurring when you execute the program. It also sounds like "make" executes the program automatically. Correct?

3) If so, you want to look in a debugger and identify the exact line where it's crashing.

4) I suspect if you trace through the code you'll see that one or more of "diff", "bucketSizeB" and/or "filled" become very large (or negative). Which would be a bug :) Which you can easily fix - once you find it.

5) Here's are good tutorials on GDB, if that happens to be a convenient debugger for you:

http://dirac.org/linux/gdb/

http://www.cs.cmu.edu/~gilpin/tutorial/

http://www.cprogramming.com/gdbtutorial.html

like image 111
paulsm4 Avatar answered Nov 15 '22 18:11

paulsm4


This works: in my Bucket(std::size_t bucketSizeB) constructor the initialiser for str should change from str(new char[bucketSizeB] to str(new char[bucketSizeB_]) (ie. use the argument passed to the cosntructor instead of using the bucketSizeB variable).

like image 5
wesrobin Avatar answered Nov 15 '22 18:11

wesrobin