2013-03-27 2 views
7

Я реализую класс со связанным списком классов, который хранит «ведра» (узлы), каждый из которых содержит предопределенное количество символов. Каждое ведро хранит указатель на следующее и предыдущее ведро, а класс списка (BucketString) сохраняет указатель на головной ковш. Я компиляция с помощью г ++, который бросает ошибкуC++: завершение вызова после вызова экземпляра 'std :: bad_alloc'

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

всякий раз, когда я запускаю код и добавить строку символов в список, используя следующий добавить метод, который содержится в моем классе ведра, и вызывается из когда это необходимо.

Код:

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

Когда выбрасывается ошибка, метод добавь вызывается из «списка» члена класса метода Append, который работает следующим образом:

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 
} 

Файл заголовка для класса ковша:

#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 
+1

Добро пожаловать в СО, но позвольте мне спросить вас: что вы пробовали? Добавили ли вы распечатки-заявления, чтобы узнать, откуда исходит ошибка? Вы использовали отладчик? (И нет, кода, который вы показали, недостаточно) –

+0

Я добавил указанные операторы печати, и именно так я знаю, что он вызывается при вызове этого метода. Странно то, что метод, похоже, работает правильно для первых 70 или около того символов, добавленных, но затем сообщение вызывается. Что еще вам понравится? К сожалению, класс «list» довольно длинный, я включу метод в класс «list» (называемый BucketString), который вызывает этот метод, если это помогает. – wesrobin

+0

bad_alloc вызывается оператором new, когда он не работает. Поскольку add использует рекурсию, возможно, вы рекурсионируете себя из памяти. – engineerC

ответ

5

Это работает: в моем Bucket(std::size_t bucketSizeB) конструктор инициализатор для str должен измениться с str(new char[bucketSizeB] на str(new char[bucketSizeB_]) (т. е. использовать аргумент, переданный cos ntructor вместо использования переменной bucketSizeB).

+0

Поскольку члены инициализируются в том порядке, в котором они объявлены. Вы должны получить предупреждение об этом, если ваши настройки компилятора достаточно высоки. – GManNickG

+1

@GManNickG, я не понимаю, почему вы получите предупреждение за его конкретную ошибку. Переменная 'bucketSizeB' была определена ранее как глобальная ... –

5

1) Вы можете предотвратить окончание с помощью блока try/catch.

2) Похоже, что это происходит при выполнении программы. Он также звучит так, как «make» выполняет программу автоматически. Верный?

3) Если это так, вы хотите посмотреть в отладчике и определить точную строку, где он сбой.

4) Я подозреваю, что если вы проследите код, вы увидите, что один или несколько «diff», «bucketSizeB» и/или «заполнены» становятся очень большими (или отрицательными). Который был бы ошибкой :) Который вы можете легко исправить - как только вы его найдете.

5) Вот хорошие учебники по GDB, если это произойдет, чтобы быть удобным отладчик для вас:

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

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

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

+0

1) скрывает ошибку и ухудшает ситуацию, она не решит проблему. 2) не имеет значения. 3) должен быть (уже есть) комментарий. –

Смежные вопросы