2013-04-18 3 views
0

Я пишу программу, чтобы показать Game of Life от Conway в C++. Мой профессор дал нам основную функцию и класс, описывающий «вселенную», мы должны реализовать функции, прототипированные в классе. Моя проблема сейчас заключается в том, чтобы заставить конструктор функционировать. Я опубликую класс, а затем напишу для конструктора. Использование GDB, когда я добираюсь до первой строки, используемой конструктором (юниверс (ширина, высота, обертка);) Я получаю следующую ошибку: libC++ abi.dylib: terminate called throwing exceptionКонструктор не работает

Полученный сигнал программы SIGABRT, Прервано. 0x00007fff876fad46 in __kill()

Любая помощь приветствуется! Код ниже.

// Conways game of life 

    class universe {    
private: 
int* array;  // A pointer to a [width]X[height] array of cells that constitutes  the universe 
       // for the game of life. A value of 1 signifies a live cell at that location. 
int width;  // The width of the universe. 
int height;  // The height of the universe 
int wrap;  // wrap = 1 means the universe wraps around on itself -- the right hand 
       // side connects to the left and the top connects to the bottom. 
       // wrap = 0 means the universe ends at the array boundaries. 
public: 
universe();   // A null constructor: sets array, width, height, and wrap to 0. 
universe(int,int,int); // Constructor to allocate space for a universe of given width (first value) 
        // height (second value) and wrap setting (third value). Sets all cells to 0. 
void display();  // Display the live cells in a graphics window. 
void setup();  // Display the universe then allow the user to interactively modify 
        // the cell arrangement using the mouse. 
void operator<<(char*); // Read in a universe from a file; first number has the width, 
          // second number is the height, 
          // third number is the wrap parameter, 
          // then 1s/0s in a 2D integer array represent living/dead cells. 
void operator>>(char*); // Save the universe to a file with the specified name (format as above). 
void operator=(universe); // Copy the contents of one universe to another. 
void operator<<(universe); // Calculate the new generation by applying the rules, then 
          // display the new generation. 
int neighbors(int,int);  // Returns the number of neighbors of the cell at i,j. 
int value(int,int);  // Returns the value at cell i,j (0 or 1). 
void setvalue(int,int,int); // Sets the value of the cell at i,j. 
void free(); // Release the memory used to store the universe. Set array = 0. 
}; 

// Implementation 


universe::universe(){ 
array =0;    
width = 0; 
height = 0; 
wrap = 0; 
} 

universe::universe(int width1,int height1,int wrap1){ 

int i=0, j=0; 
int* array = new int[width*height-1];  
for(i=0;i<width;i++){ 
    for(j=0;j<height;j++){ 
     array[j*width+i] =0; 
         } 
        } 
width = width1; 
height =height1; 
wrap = wrap1; 
} 
+0

Вам не хватает конструктора копирования и деструктора (функции 'free()' делают ** не ** сокращают его). Кроме того, я бы предложил контейнер, но я готов поспорить, что вам запрещено использовать его. – chris

+1

Вы видите конструктор с 3 параметрами, который выделяет локальный массив (и никогда не назначает его, тем самым утечка) ваших ** членов ** 'width' и' height' * before * они фактически назначены? Когда это завершено, у вас есть неопределенное значение для 'array', утечка памяти неопределенного размера и назначенные значения ширины и высоты. – WhozCraig

+0

Вы должны прочитать некоторые статьи/книги на C++. Этот код похож на какого-то гротескного любовного ребенка C и C++. RAII, контейнеры и списки инициализации - ваши друзья. –

ответ

1

Есть так много вещей неправильно с оригинальным кодом будет трудно просто отбарабанить список, но я могу попробовать:

  1. Пользователи width и height используются для выделения члена проклейки, прежде чем они даже содержат определенные значения. Поэтому их использование ценности является неопределенным, и поэтому распределение памяти показывает неопределенное поведение.

  2. Распределение хранится локальным указателем, а затем быстро теряется после выхода из конструктора. он никогда не присваивается переменной array. Таким образом, вы теряете память. Кроме того, поскольку array (член) никогда не назначается, его значение неопределенно даже после построения, и поэтому любой доступ (чтение или запись) с использованием его адреса содержит неопределенное поведение.

  3. У вас нет деструктора класса для очистки памяти, выделенной в конструкторе или функции-члене. (предполагая, что вы правильно исправьте конструктор 3-param, и на самом деле сохраняет указатель на распределение памяти в элементе array). Поэтому это утечка памяти при уничтожении (при условии, что конструктор 3-парама фиксирован), или на построении (при условии, что конструктор с 3 параметрами НЕ фиксирован).

  4. Вы - width и height Участники в настоящее время могут принять отрицательные значения, которые не имели бы смысла на самом деле использовать, и могут привести к потенциальному хаосу с вашим распределением.Все члены, не предназначенные явно , допускают отрицательные значения должны быть беззнаковых типов, size_t являются общими.

  5. Ни у конструктора нет списка инициализаторов. Они оба должны.

  6. class universe динамически выделяет память для локальной переменной-члена. Без создания виртуального деструктора, копирования-конструктора и оператора присваивания будут реализованы реализации по умолчанию для компилятора, и они, в конечном итоге, вызовут утечку памяти или повреждение памяти. Этот код должен практиковать The Rule of Three, и в настоящее время нет.

  7. Ваша текущая логика размера выделения в конструкторе с 3 параметрами отключена одним элементом. (-1) там не принадлежит, и петли сразу же после этого напишут один элемент за выделенным размером как написанный. Это undefined поведение.

  8. Вы используете имя стандартного библиотечного класса как имя локально определенной переменной/класса/члена. Хотя официально не «ошибочно», настоятельно рекомендуется вы избегаете этой практики.

Я сильно советуют solid C/C++ book.

+0

Это отличный пост! – Patashu

+0

Большое вам спасибо! Я понимаю, что у меня есть длинный путь с C++, и это назначение разочаровывает (нам не разрешено редактировать класс юниверса или главную функцию). Я понял после публикации вопросов 1, 2 и 4, которые я исправил. Я работаю через 3,5,6 и 8 (читая некоторую литературу), но я уверен, что я прав в отношении 7. Я выделяю 1D-массив, который будет содержать индекс для каждой точки данных в гипотетической [ширине] [высота] сетка. Если ширина равна 5 и высота равна 10 width * height = 50, однако для создания 50 индексов я хочу выделить индекс размера 49. – ConnorDurkin

+0

Что касается вашего размера выборки (5x10), ** вы хотите 50 узлов (5 * 10). ** Они * доступны * с использованием индексов 0..49, но вы все еще хотите 50. Не путайте количество узлов с максимальным индексом, используемым для доступа к ним. Первый всегда один * больше *, чем последний. Если вам нужна матрица 5x10, вам нужно 50 узлов, ** не ** 49. Надеюсь, это имеет смысл. – WhozCraig

2
int* array = new int[width*height-1]; 

должен быть

array = new int[width*height-1]; 

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

Между тем, вы должны сначала присвоить значения width и height перед их использованием с помощью new.

Ваши коды должны выглядеть следующим образом:

universe::universe(int width1,int height1,int wrap1){ 
    width = width1; 
    height =height1; 
    wrap = wrap1; 
    array = new int[width*height-1];  
    for(int i=0; i<width; i++){ 
     for(int j=0; j<height; j++){ 
     array[j*width+i] =0; 
     } 
    } 
} 

Лучше поставить член int*array после wrap если вы хотите инициализации списка.

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