Страницы

Поиск по вопросам

пятница, 31 января 2020 г.

C++. Правильное удаление динамического двумерного массива

#cpp #массивы #классы #указатели


Всем привет. Я новичок в программировании и только начинаю многое осваивать(хотя
и имею кое-какую подготовку, но считать её хоть сколь-либо серьезной смешно). Знакомлюсь
с классами, пытаясь соорудить нечто для работы с матрицами. Код реализации не важен,
важно то, что получаю ошибку:
http://prntscr.com/e6y5on
Ключевой вопрос в том, как её исправить. 

Matrix.h:

#ifndef MATRIX_H
#define MATRIX_H

class Matrix
{
  private:
    int m_rows = 1;
    int m_cols = 1;
    int** m_matrix = new int* [m_rows];

  public:
    Matrix(int rows, int cols);

    void SetSize(int rows, int cols);
    void Create();

    int rows();
    int cols();

    ~Matrix();

};
#endif


Matrix.cpp:

#include 
#include 
#include "matrix.h"

using namespace std;

Matrix::Matrix(int rows, int cols)
{
    SetSize(rows, cols);
    Create();
}

void Matrix::SetSize(int rows, int cols)
{
    m_rows = rows;
    m_cols = cols;
}

void Matrix::Create()
{
    for (int i = 0; i < m_rows; i++)
        m_matrix[i] = new int[m_cols];

    cout << "Matrix created with " << m_rows << " rows and " << m_cols <<
         " cols." <<         endl;
}


int Matrix::rows()
{
    return m_rows;
}

int Matrix::cols()
{
    return m_cols;
}

Matrix::~Matrix()
{
    for (int i = 0; i < m_rows; i++)
        delete[] m_matrix[i];

    delete[] m_matrix;
    cout << "Matrix deleted" << endl;
}


main.cpp:

int main()
{
    Matrix m(2,2);
    return 0;
}


При пошаговой проверке в Visual Studio программа сыплется на удалении внешнего указателя
delete[] m_matrix; 
Собственно, прошу помочь =)
    


Ответы

Ответ 1



Давайте разбираться. int m_rows = 1; int m_cols = 1; int** m_matrix = new int* [m_rows]; Итак, у вас сразу выделяется память и создается матрица 1x1. Поскольку в конструкторе Matrix::Matrix(int rows, int cols) у вас нет инициализации членов, они инициализированы по умолчанию этой матрицей. Но что вы делаете дальше? Вы переписываете m_rows и m_cols, и в уже выделенный массив для ОДНОГО указателя записываете их m_rows, т.е. в данном конкретном случае - два. Вот вам и источник ваших неприятностей. Ваша попытка исправить ситуацию - это просто попытка не заметить ошибку. Ни к чему хорошему привести это не может. В следующий раз вы запишете туда их с десяток, и таки засорите память основательнее, только и всего. Вот как по-хорошему должна выглядеть ваша матрица: class Matrix { private: int m_rows; int m_cols; int** m_matrix; public: Matrix(int rows, int cols); void SetSize(int rows, int cols); void Create(); int rows(); int cols(); ~Matrix(); }; Matrix::Matrix(int rows, int cols) :m_rows(rows),m_cols(cols) { m_matrix = new int*[m_rows]; for (int i = 0; i < m_rows; i++) m_matrix[i] = new int[m_cols]; cout << "Matrix created with " << m_rows << " rows and " << m_cols << " cols." << endl; } Matrix::~Matrix() { for (int i = 0; i < m_rows; i++) delete[] m_matrix[i]; delete[] m_matrix; cout << "Matrix deleted" << endl; }

Ответ 2



Судя по всему вы создаёте int** m_matrix размером один, а потом передаёте параметр 2 и думаете что там 2 строки. Видимо вам лучше создавать динамичкский массив в методе Create: void Matrix::Create(){ m_matrix = new int*[m_rows]; for (int i = 0; i < m_rows; i++) m_matrix[i] = new int[m_cols]; cout << "Matrix created with " <

Ответ 3



В классе имеется обращение за пределы выделенной памяти. Если вы добавите следуюшие два предложения в конструктор Matrix::Matrix(int rows, int cols) { std::cout << "m_rows = " << m_rows << std::endl; std::cout << "m_cols = " << m_cols << std::endl; SetSize(rows, cols); Create(); } то при создании объекта класса на консоль будет выдано сообщение m_rows = 1 m_cols = 1 Это означает, что перед тем. как тело конструктора получило управление, была выполнена инициализация членов класса int m_rows = 1; int m_cols = 1; int** m_matrix = new int* [m_rows]; в результате которой была выделена память для массива указателей из одного указателя типа int *. Однако в функции Create, так как в общем случае значение m_rows, заданное в конструкторе, может отличаться от 1, то происходит выход за пределы динамически выделенного массива. void Matrix::Create() { for (int i = 0; i < m_rows; i++) m_matrix[i] = new int[m_cols]; cout << "Matrix created with " << m_rows << " rows and " << m_cols << " cols." << endl; } Нет никакого смысла инициализировать члены класса в определении класса вместо того, чтобы инициализировать их в конструкторе. Имейте в виду, что вам необходимо также определить конструктор копирования и копирующий оператор присваивания, или определить их как удаленные.

Ответ 4



Вы неправильно выделяете память. Эту строку: int** m_matrix = new int*[m_rows]; необходимо перенести из заголовка (.h) в реализацию функции Create(): void Matrix::Create() { m_matrix = new int*[m_rows]; for (int i = 0; i < m_rows; i++) m_matrix[i] = new int[m_cols]; } В заголовке оставляете только объявление указателя: int** m_matrix; Деструктор возвращаете к вашему первоначальному виду: Matrix::~Matrix() { for (int i = 0; i < m_rows; i++) delete[] m_matrix[i]; delete[] m_matrix; }

Ответ 5



Нашёл ответ на собственный вопрос. Не знаю дело ли в классе или же это так правильно, но удаления for (int i = 0; i < m_rows; i++) delete[] m_matrix[i]; Оказалось более чем достаточно.

Комментариев нет:

Отправить комментарий