LINUX.ORG.RU

[C++] Динамический двумерный массив объектов.

 


0

0

Здравствуйте!

Делаю я сейчас абстрактный класс «таблица». Эта таблица состоит из объектов - «ячеек». В момент создания объекта «таблица» известно количество ячеек по горизонтали и вертикали.

В процессе работы я нашел неплохое описание, как делать многомерные динамические массивы. «C++. Бархатный путь. Часть 1. Страница 76. Многомерные динамические массивы.» http://www.cyberguru.ru/programming/cpp/cpp-velvet-way-page76.html

По аналогии делаю и свой класс. Заголовок

class EditorAbsTable
{
public:
 EditorAbsTable(int x, int y, QString table_text);
 ~EditorAbsTable(void);

private:
 void create_cells_array(int x, int y);
 void delete_cells_array(void);
 void clear_table(void);

 int columns;
 int rows;

 EditorAbsTableCell **cells; // Ячейки таблицы
};

Реализация

// Конструктор
EditorAbsTable::EditorAbsTable(int x, int y, QString table_text)
{
 create_cells_array(x,y);
 clear_table();
 convert_table_to_internal(table_text);
}

// Деструктор
EditorAbsTable::~EditorAbsTable(void)
{
 delete_cells_array();
}

// Выделение памяти под двумерный массив таблицы
void EditorAbsTable::create_cells_array(int x, int y)
{
 cells=new EditorAbsTableCell*[x];
 for(int i=0;i<x;i++)
  cells[i]=new EditorAbsTableCell[y];
}

// Удаление памяти, отведенной под двумерный массив таблицы
void EditorAbsTable::delete_cells_array(void)
{
 for(int i=0;i<columns;i++)
  delete []cells[i];

 delete []cells;
}

// Очистка таблицы
void EditorAbsTable::clear_table(void)
{
 for(int i=0;i<columns;i++)
  for(int j=0;j<rows;j++)
   cells[i][j].clear();
}

Проблема в том, что возникает сегфолт в методе clear_table(). Сегфолт возникает при вызове cells[j].clear() когда i становится равным 1. (Пока i=0 а j=0..n, вызов cells[j].clear() срабатывает нормально). То есть, обрабатывается только один столбец.

Я так подозреваю, что сегфолт происходит из-за того, что по указанным координатам, начиная с cells[1...x][...] ссылок на объекты-ячейки просто нет, так как они не были созданы в методе create_cells_array(). Поэтому не может вызваться метод clear() для соответсвующей ячейки.

Но вот смотрю я на код метода create_cells_array(), и не пойму, как же его переделать так, чтобы и память для каждой ячейки выделилась, и конструктор для каждой ячейки сработал.

Как это сделать?


наверное, стоит показать, что делает convert_table_to_internal,
и проверить, точно ли cells[1][...] равна 0

и еще что-то не видно, где инициализируются columns и rows

kaj
()

// Выделение памяти под двумерный массив таблицы void EditorAbsTable::create_cells_array(int x, int y) ... for(int i=0;i<x;i++) cells[i]=new EditorAbsTableCell[y];

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

shuthdar ★★★
()
Ответ на: комментарий от kaj

> наверное, стоит показать, что делает convert_table_to_internal,
До него дело не доходит, сегфолт раньше идет.

> и проверить, точно ли cells[1][...] равна 0

Да, дебагер показывает 0 (хотя мог бы показать и мусор)

> и еще что-то не видно, где инициализируются columns и rows

Ну это я упрощал перед постингом код... Инициализация в конструкторе конечно идет.

columns=x;
rows=y;

xintrea
() автор топика
Ответ на: комментарий от shuthdar

> for(int i=0;i<x;i++) cells[i]=new EditorAbsTableCell[y];

> тут ты создаёшь только ссылку на массив EditorAbsTableCell, каждый

> объект EditorAbsTableCell тебе надо ещё отдельно проинициализировать.


Да, именно об этом я и думаю. Только не могу понять как эту инициализацию каждого объекта написать?

xintrea
() автор топика
Ответ на: комментарий от xintrea

элементарно :)

void EditorAbsTable::create_cells_array(int x, int y)
{
cells=new EditorAbsTableCell*[x];
  for(int i=0;i<x;i++) {
    cells[i]=new EditorAbsTableCell[y];
    for (int j = 0; j < y; j++)
      cells[i][j] = new EditorAbsTableCell();
  }
}

форматирование такое форматирование...

shuthdar ★★★
()
Ответ на: комментарий от Absurd

> Сделай std::vector< std::vector<QString> > и не парь себе мозг. Или даже std::map<int, std::map<int, QString> >.

Не, там много кода, код весь написан в удобочитаемом стиле massiv[][]. Раньше это все работало со статическми массивом у которого размеры заданы "с запасом". Щас минимальными средствами переделываю на работу с динамическим массивом.

xintrea
() автор топика
Ответ на: комментарий от shuthdar

попробуйте заменить EditorAbsTableCell на int и скомпилировать :)
new EditorAbsTableCell[y] создает массив объектов, а не указателей, если это тот же с++, что и раньше
и для них вызываются констр. по умолчанию

kaj
()
Ответ на: комментарий от shuthdar

Блин, что-то дикое происходит на строчке

cells[i][j] = new EditorAbsTableCell();

компиляция вываливается с ошибкой

/media/sda2/opt/qt_4_5_sdk/qt/include/QtCore/qobject.h: In member function 'EditorAbsTableCell& EditorAbsTableCell::operator=(const EditorAbsTableCell&)':
/media/sda2/opt/qt_4_5_sdk/qt/include/QtCore/qobject.h:302: Error: ошибка: 'QObject& QObject::operator=(const QObject&)' is private
src/editor/editorabstablecell.h:10: Error: ошибка: в данном контексте
src/editor/editorabstable.cpp: In member function 'void EditorAbsTable::create_cells_array(int, int)':
src/editor/editorabstable.cpp:53: Error: замечание: synthesized method 'EditorAbsTableCell& EditorAbsTableCell::operator=(const EditorAbsTableCell&)' first required here

никаких операторов "=" я не переопределял, конструктор EditorAbsTableCell в секции public, само собой.

xintrea
() автор топика
Ответ на: комментарий от kaj

мне сейчас компилировать нечем. если так, то ок, значит с поведением pure C попутал :)

shuthdar ★★★
()
Ответ на: комментарий от kaj

> new EditorAbsTableCell[y] создает массив объектов, а не указателей, если это тот же с++, что и раньше и для них вызываются констр. по умолчанию

Ну то есть, вариант создания массива в топике правильный?
Тогда почему сегфолт возникает?

xintrea
() автор топика
Ответ на: комментарий от xintrea

вы, наверное, не весь код запостили?
вот это компилируется и работает:


typedef int EditorAbsTableCell ;
typedef int QString ;



class EditorAbsTable
{
public:
EditorAbsTable(int x, int y, QString table_text);
~EditorAbsTable(void);

private:
void create_cells_array(int x, int y);
void delete_cells_array(void);
void clear_table(void);

int columns;
int rows;

EditorAbsTableCell **cells; // Ячейки таблицы
};


// Конструктор
EditorAbsTable::EditorAbsTable(int x, int y, QString table_text)
{
columns = x;
rows = y;
create_cells_array(x,y);
clear_table();
}

// Деструктор
EditorAbsTable::~EditorAbsTable(void)
{
delete_cells_array();
}

// Выделение памяти под двумерный массив таблицы
void EditorAbsTable::create_cells_array(int x, int y)
{
cells=new EditorAbsTableCell*[x];
for(int i=0;i<x;i++)
cells[i]=new EditorAbsTableCell[y];
}

// Удаление памяти, отведенной под двумерный массив таблицы
void EditorAbsTable::delete_cells_array(void)
{
for(int i=0;i<columns;i++)
delete []cells[i];

delete []cells;
}


// Очистка таблицы
void EditorAbsTable::clear_table(void)
{
for(int i=0;i<columns;i++)
for(int j=0;j<rows;j++)
cells[i][j] ++;
}


int main ()
{

EditorAbsTable tbl (5, 5, 0);

return 0;
}


kaj
()
Ответ на: комментарий от xintrea

>Не, там много кода, код весь написан в удобочитаемом стиле massiv[][]

Оба метода предполагают доступ через [][]

Absurd ★★★
()

Все, парни, разобрался. Код в заглавном сообщении валидный, это я прогнался с данными. Неправильно исходный размер таблицы считался при наличии вложенной таблицы.

xintrea
() автор топика

Мне кажется если заранее известен размер таблицы, то намного проще сразу одним malloc выделять весь массив, и одним free освобождать, когда он не нужен, чем хранить указатель на каждую строку, и выделять и освобождать каждую строку.

Т. е. код представляет из себя что-то вроде

Element* array_ptr; int _num_row; int _num_col;

void InitTable(int num_row,int num_col) { int total_size = num_row * num_col * sizeof(Element); array_ptr = (Element*) malloc(total_size); }

void FreeTable() { free(array_ptr); }

Element* GetItem(int r,int c) { return array_ptr[_num_col*r+c]; }

pathfinder ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.