Правило трех упражнений неожиданный результат

Я стараюсь изучать основы C++ в свободное время и следую упражнениям из книги. Во-первых, когда я ввожу 9 как строку и 8 как столбец, я получаю ошибку освобождения malloc. Во-вторых, я получаю 0 в качестве вывода, я не вижу, что я ввожу. Я хочу написать программу, потому что могу усилить правило трех. Это конечно не домашняя работа. Кроме того, я думаю, что это сложный вопрос и эффективный вопрос. Если на вопрос можно будет ответить, это будет полезно. Поскольку я искал в Google, я не могу найти что-то приличное о решении. Кроме того, вы можете проверить мой конструктор копирования, оператор присваивания и деструктор и сказать мне, где мои ошибки?

Напишите класс TwoD, который реализует двумерный динамический массив значений типа double, используя идеи из этого дисплея в своих конструкторах. У вас должен быть закрытый член типа указатель для удвоения, указывающий на динамический массив, и два значения типа int (или unsigned int), которые являются MaxRows и MaxCols. Вы должны предоставить конструктор по умолчанию, для которого вы должны выбрать максимальные размеры строк и столбцов по умолчанию и параметризованный конструктор, который позволяет программисту устанавливать максимальные размеры строк и столбцов. Кроме того, вы должны предоставить функцию-член void, которая позволяет устанавливать конкретную запись строки и столбца, а также функцию-член, которая возвращает конкретную запись строки и столбца в качестве значения типа double. Примечание: Перегрузка [ ] затруднена или невозможна (в зависимости от деталей), поэтому она работает так, как вы хотели бы для двумерных массивов. Поэтому просто используйте функции доступа и мутатора, используя обычную функцию обозначения. Перегрузите оператор + как функцию-друг, чтобы добавить два двумерных массива. Эта функция должна возвращать объект TwoD, чья i-я строка, элемент j-го столбца является суммой i-й строки, элемента j-го столбца объекта TwoD левого операнда и i-й строки, элемента j-го столбца объекта TwoD правого операнда. Предоставьте конструктор копирования, перегруженный оператор = и деструктор. Объявите функции-члены класса, которые не изменяют данные, как постоянные члены.

Мои усилия

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

class TwoD
{
public:
    TwoD();
    TwoD(int row, int column);
    void setRowCol();
    double getVal(int row, int column);
    friend const TwoD operator +(const TwoD& first, const TwoD& second);
    int getterRow() const;
    int getterCol() const;
    void setterRow(int row);
    void setterCol(int column);
    TwoD(const TwoD& object);
    TwoD& operator =(const TwoD& rightSide);
    void putArr() const;
    ~TwoD();
    static TwoD constructFromUserInput();
private:
    int MaxRows;
    int MaxCols;
    double **arr;
};

int main(int argc, char const *argv[])
{
    cout << "All size of TwoD object must be same\n\n";

    TwoD arr1 = TwoD::constructFromUserInput();
    TwoD arr2 = TwoD::constructFromUserInput();

    TwoD arr3;

    arr3 = arr1 + arr2;

    TwoD arr4(arr3);
    arr1.putArr();
    arr2.putArr();
    arr3.putArr();
    arr4.putArr();

    return 0;
}
void TwoD::setRowCol()
{
    int r_user;
    int c_user;
    cout << "Enter num of rows => ";
    cin  >> r_user;
    cout << "Enter num of columns => ";
    cin  >> c_user;

    MaxRows = r_user;
    MaxCols = c_user;

    TwoD(MaxRows,MaxCols);

}
TwoD::TwoD(int row, int column)
: MaxRows(row), MaxCols(column)
{
    arr = new double*[row];
    for (int i = 0; i < row; i++)
    {
        arr[i] = new double[column];
    }

    for (int i = 0; i < MaxRows; i++)
    {
        for (int j = 0; j < MaxCols; j++)
        {
            cout << "Enter for " << i << j << "=> ";
            cin  >> arr[i][j];
        }
    }
}
TwoD::TwoD()
: MaxRows(2), MaxCols(2)
{
    arr = new double*[2];
    for (int i = 0; i < 2; i++)
    {
        arr[i] = new double[2];
    }
}
double TwoD::getVal(int row, int column)
{
    return arr[row][column];
}
const TwoD operator +(const TwoD& first, const TwoD& second)
{
    TwoD sum;
    for (int i = 0; i < first.MaxRows; i++)
    {
        for (int j = 0; j < first.MaxCols; j++)
        {
            sum.arr[i][j] = first.arr[i][j] + second.arr[i][j];
        }
    }
    return sum;
}
TwoD::TwoD(const TwoD& object)
{
    MaxRows = object.MaxRows;
    MaxCols = object.MaxCols;

    arr = new double*[MaxRows];
    for (int i = 0; i < MaxRows; i++)
    {
        arr[i] = new double[MaxCols];
    }

    for ( int i = 0; i < MaxRows; i++ )
    {
        for ( int j = 0; j < MaxCols; j++ )
        {
            arr[i][j] = object.arr[i][j];
        }
    }
}
TwoD::~TwoD()
{
    for (int i = 0; i < MaxRows; i++)
        delete [] arr[i];
    delete [] arr;
}
TwoD& TwoD::operator =(const TwoD& rightSide)
{
    if (this == &rightSide)
    {
        return *this;
    }

    for (int i = 0; i < MaxRows; i++)
        delete [] arr[i];
    delete [] arr;

    arr = new double*[rightSide.MaxRows];
    for (int i = 0; i < rightSide.MaxRows; i++)
    {
        arr[i] = new double[rightSide.MaxCols];
    }

    MaxRows = rightSide.MaxRows;
    MaxCols = rightSide.MaxCols;

    for (int i = 0; i < MaxRows; i++)
    {
        for (int j = 0; j < MaxCols; j++)
        {
            arr[i][j] = rightSide.arr[i][j];
        }
    }
    return *this;
}
void TwoD::putArr() const
{
    for (int i = 0; i < MaxRows; i++)
    {
        for (int j = 0; j < MaxCols; j++)
        {
            cout << arr[i][j] << " ";
        }
        cout << endl;
    }
}
int TwoD::getterRow() const
{
    return MaxRows;
}
int TwoD::getterCol() const
{
    return MaxCols;
}
void TwoD::setterRow(int row)
{
    MaxRows = row;
}
void TwoD::setterCol(int column)
{
    MaxCols = column;
}
TwoD TwoD::constructFromUserInput()
{
    int r_user;
    int c_user;
    cout << "Enter num of rows => ";
    cin  >> r_user;
    cout << "Enter num of columns => ";
    cin  >> c_user;

    // Construct an object.
    TwoD obj(r_user, c_user);

    // Return the object
    return obj;
}

2 ответа

  1. ваш конструктор копирования создает массивы, но никогда не копирует содержимое. Оператор присваивания копии делает это правильно. В этом отношении у вас есть множество дублированных new[] петли, пара delete[] циклы, и у вас должно быть два цикла копирования. Разложите их в функции, и вам нужно сделать их правильно только один раз.

  2. sum создает объект размера по умолчанию, а затем, вероятно, переопределяет размеры строк и столбцов. Обычная (простая и правильная) реализация заключается в создании локальной копии левого аргумента (с использованием копии ctor, которую вы исправили выше), и пересылке operator+=, С этим оператором гораздо проще разобраться.

  3. у вас есть способ распечатать эти матрицы. Сделай это! Делай это везде! Это позволяет легко увидеть, на каком этапе все пошло не так.

  4. эта книга звучит не очень хорошо. Он учит плохой практике без видимой причины (оператор + трюк является стандартным, вы должны использовать unique_ptr если вы не можете использовать vector и тд и тп)


Редактирование: Я отвечу на некоторые комментарии здесь, потому что они могут превратиться в сеанс чата, и я не хочу тратить на это больше времени.

  • Я исправил конструктор копирования, верно?

    Это хорошее время, чтобы выяснить, как тестировать и отлаживать код. Добавьте операторы печати, используйте отладчик, разбейте вещи на функции, которые вы можете протестировать, а затем напишите тесты для них.

  • что вы имеете в виду пару delete[] петли и имеющие две копии копий

    Ищите петли в вашем коде. Я вижу 3 звонка new[] Все делают по существу одно и то же. Я вижу 2 звонка delete[] один в деструкторе и один в операторе присваивания копии. Просто найдите свой собственный код для for ключевое слово!

  • Я действительно не нахожу способ распечатать матрицы

    так где же TwoD::putArr родом из? по общему признанию ostream& operator<<(ostream&, TwoD const &) было бы лучше назвать его, но вы написали его, чтобы вы могли использовать его.

  • Я не могу получить деструктор в main ()

    Вы не можете остановить вызов деструктора по окончании main - тогда ваши объекты выходят из области видимости. Просто установите точку останова в деструкторе, и она будет вызвана.

  • Поскольку arr является частным, как я могу проверить?

    вы все еще можете увидеть его в отладчике, вы можете распечатать содержимое (как указано выше), вы все равно можете вызвать getVal из модульного теста, вы можете просто сделать это public пока вы не выясните свои проблемы

Проблема с вашим кодом:

void TwoD::setRowCol()
{
    int r_user;
    int c_user;
    cout << "Enter num of rows => ";
    cin  >> r_user;
    cout << "Enter num of columns => ";
    cin  >> c_user;

    MaxRows = r_user;
    MaxCols = c_user;

    ///
    /// This constructs a new TwoD object but does not change
    /// object on which the function was invoked.
    ///
    TwoD(MaxRows,MaxCols);    
}

Способы решения проблемы:

Обновить данные участника

void TwoD::setRowCol()
{
    int r_user;
    int c_user;
    cout << "Enter num of rows => ";
    cin  >> r_user;
    cout << "Enter num of columns => ";
    cin  >> c_user;

    // Delete the current memory
    for (int i = 0; i < MaxRows; i++)
    {
       delete [] arr[i];
    }

    delete [] arr;

    MaxRows = r_user;
    MaxCols = c_user;

    // Allocate new memory.
    arr = new double*[MaxRows];
    for (int i = 0; i < MaxRows; i++)
    {
       arr[i] = new double[MaxCols];
    }

    // Now read the data.
    for (int i = 0; i < MaxRows; i++)
    {
        for (int j = 0; j < MaxCols; j++)
        {
            cout << "Enter for " << i << j << "=> ";
            cin  >> arr[i][j];
        }
    }
}

Создайте функцию, которая возвращает новый объект

Я рекомендую этот метод.

Сначала обновите конструктор, который принимает строку и столбец, чтобы у него не было кода для чтения данных из пользовательского ввода.

TwoD::TwoD(int row, int column)
: MaxRows(row), MaxCols(column)
{
    arr = new double*[row];
    for (int i = 0; i < row; i++)
    {
        arr[i] = new double[column];
    }
}

Во-вторых, добавить static функция-член для создания объекта из пользовательского ввода.

static TwoD constructFromUserInput();

и реализовать его как:

TwoD TwoD::constructFromUserInput()
{
    int r_user;
    int c_user;
    cout << "Enter num of rows => ";
    cin  >> r_user;
    cout << "Enter num of columns => ";
    cin  >> c_user;

    // Construct an object.
    TwoD obj(r_user, c_user);

    // Now read the data.
    for (int i = 0; i < r_user; i++)
    {
        for (int j = 0; j < c_user; j++)
        {
            cout << "Enter for " << i << j << "=> ";
            cin  >> obj.arr[i][j];
        }
    }

    // Return the object
    return obj;
}

В-третьих, используйте новую функцию из main,

int main(int argc, char const *argv[])
{
   cout << "All size of TwoD object must be same\n\n";

   TwoD arr1 = TwoD::constructFromUserInput();
   TwoD arr2 = TwoD::constructFromUserInput();

   TwoD arr3;

   arr3 = arr1 + arr2;
   arr1.putArr();
   arr2.putArr();
   arr3.putArr();

   return 0;
}
Другие вопросы по тегам