Мне нужна помощь. Теперь я пытаюсь создать класс Matrix, но моя программа зависает каждый раз, когда я запускаю ее в Visual Studio 2013. Я думаю, что есть некоторые проблемы с конструктором копирования. Вот весь код. `

class Matrix
{
private:
    int** matrix;
    int X; // Matrix rows
    int Y; // Matrix columns
public:
    // Default Constructor
    Matrix()
    {
        X = 0;
        Y = 0;
        matrix = NULL;
    }
    // Constructor with parameters
    Matrix(int _X, int _Y)
    {
        srand(time(NULL));

        X = _X;
        Y = _Y;
        matrix = new int*[X];

        for (int i = 0; i < X; i++)
                matrix[i] = new int[Y];

        for (int i = 0; i < X; i++)
        {
            for (int j = 0; j < Y; j++)
            {
                matrix[i][j] = rand() % 100;
            }
        }

    }
    // Copy constructor
    Matrix(const Matrix& N)
    {
        X = N.X;
        Y = N.Y;

        matrix = new int*[X];

        for (int i = 0; i < X; i++)
            matrix[i] = new int[Y];

        for (int i = 0; i < X; i++)
        {
            for (int j = 0; j < Y; j++)
            {
                matrix[i][j] = N.matrix[i][j];
            }
        }
    }
    // Destructor
    ~Matrix()
    {
        for (int i = 0; i < X; i++)
            delete[] matrix[X];
    }
    //--------------------------------------
    void ShowMatrixOnScreen()
    {
        for (int i = 0; i < X; i++)
        {
            for (int j = 0; j < Y; j++)
                cout << matrix[i][j] << "   ";

            cout << endl << endl;
        }
    }
};

void main() 
{
    Matrix x(4, 2);
    x.ShowMatrixOnScreen();
}

`

Функция «ShowMatrixOnScreen» выводит матрицу «x» на экран, но затем консоль зависает.

2
BrainOverflow 28 Окт 2015 в 17:14

2 ответа

Лучший ответ

В вашем деструкторе есть утверждение delete[] matrix[X];

matrix[X] не существует, поэтому вы освобождаете память, которая не выделена вам, что является неопределенным поведением. Вместо этого должно быть delete [] matrix[i]!

Более того, как указал Влад из Москвы, рекомендуется delete всю память, поэтому вам также следует рассмотреть возможность добавления delete [] matrix, чтобы удалить одномерный массив указателей, который вы разместили с помощью {{X2 }}

7
user007 28 Окт 2015 в 14:40

Проблема в том, что ваш деструктор недействителен

Прежде всего в этом цикле

    for (int i = 0; i < X; i++)
        delete[] matrix[X];

Он пытается получить доступ к несуществующему элементу matrix[X] за пределами выделенного массива. Допустимый диапазон для индексов: [0, X - 1]

Итак, вы должны написать

    for (int i = 0; i < X; i++)
        delete[] matrix[i];
                       ^^^

Но этот цикл действителен, только если matrix не равно nullptr. Следовательно, перед циклом вы должны проверить, равно ли matrix nullptr или нет.

А также нужно удалить память, выделенную первому одномерному массиву

delete [] matrix;

Таким образом деструктор будет выглядеть как

~Matrix()
{
    if ( matrix )
    {
        for ( int i = 0; i < X; i++ ) delete []matrix[i];
    }

    delete []matrix;
}

Также в конструкторе копирования вы должны также проверить, не равен ли член данных matrix скопированного объекта nullptr

// Copy constructor
Matrix(const Matrix& N)
{
    X = N.X;
    Y = N.Y;

    if ( N.matrix )
    {
        matrix = new int*[X];

        for (int i = 0; i < X; i++)
            matrix[i] = new int[Y];

        for (int i = 0; i < X; i++)
        {
            for (int j = 0; j < Y; j++)
            {
                matrix[i][j] = N.matrix[i][j];
            }
        }
    }
}

Было бы намного лучше, если бы члены данных X и Y имели тип size_t. В противном случае вам также необходимо проверить, не отрицательны ли они.

Выделение памяти может быть размещено в отдельной частной функции-члене.

Например

int ** allocate( size_t m, size_t n )
{
    int **p = nullptr;

    if ( n != 0 && m != 0 )
    {
        matrix = new int *[m];

        for ( size_t i = 0; i < m; i++ ) matrix[i] = new int[n];
    }

    return p;
}

В определении класса элементы данных X и Y должны предшествовать матрице элементов данных

private:
    int X; // Matrix rows
    int Y; // Matrix columns    
    int** matrix;

В этом случае вы можете использовать список конструкторов mem-initializer для инициализации членов данных класса.

Например

// Constructor with parameters
Matrix(int X, int Y) : X( X ), Y( Y ), matrix( allocate( X, Y ) )
{
   if ( matrix )
   {
       srand(time(NULL));

        for (int i = 0; i < X; i++)
        {
            for (int j = 0; j < Y; j++)
            {
                matrix[i][j] = rand() % 100;
            }
        }
    }
}

И конструктор по умолчанию может быть определен как

// Default Constructor
Matrix() : Matrix( 0, 0 )
{
}

В свою очередь конструктор копирования может быть определен как

// Copy constructor
Matrix( const Matrix &N ) : X( N.X ), Y( N.Y ), matrix( allocate( N.X, N.Y ) )
{
    if ( matrix )
    {
        for (int i = 0; i < X; i++)
        {
            for (int j = 0; j < Y; j++)
            {
                matrix[i][j] = N.matrix[i][j];
            }
        }
    }
}

И вы должны также определить оператор присваивания копии или определить его как удаленный. В противном случае возникнут проблемы при попытке присвоить один объект класса другому.

Учтите, что функция main должна иметь возвращаемый тип int

int main ()

3
Vlad from Moscow 28 Окт 2015 в 14:58