运算符重载为包含2d数组的类

时间:2013-11-10 19:30:19

标签: c++ arrays pointers matrix

从方法matrix matrix::operator+(const matrix& right)返回对象后,整个数组似乎被删除了!让我们在下面的简化示例中描述这个奇怪的问题:

main.cpp中:

#include "matrix.h"
#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    matrix a("a.mt");
    matrix b("b.mt");

    matrix d(a.getRows(),a.getColumns());

    d = a+b;

    std::cout<<"hooray!";
    return 0;
}

matrix.h:

#ifndef H_MATRIX
#define H_MATRIX

#include <string>

struct field
{
    int row; 
    int column;
    double value;
};

class matrix
{
private:
    int c; //columns
    int r; //rows

    field** b; //2d array
    void allocmem();
public:
    matrix(int rows,int columns);
    matrix(std::string filename);
    ~matrix();

    void read(std::string fname);
    matrix operator+(const matrix& right);
    matrix& operator=(const matrix& right); //deep copy
    int getColumns() const;
    int getRows() const;
};

#endif

matrix.cpp

#include "matrix.h"
#include <string>
#include <fstream>
#include <iostream>

void matrix::allocmem()
{
    b = new field*[r];

    for(int i=0; i < r; i++)
        b[i] = new field[c];
}

matrix::matrix(int rows,int columns) 
{
    c = columns;
    r = rows;

    allocmem();
}

matrix::matrix(std::string fName)
{
    read(fName);
}

matrix::~matrix()
{
    for(int i=0; i<r;i++)
        delete [] b[i];

    delete b;
}

void matrix::read(std::string fname) //load matrix from file
{

    std::ifstream is;

    is.open(fname);

    is>>r>>c; //get matrix dimensions
    allocmem();

    //go to the first row
    char dull = is.peek();
    while(dull != '\n'){dull = is.get();}


    for(int i=0;i<r;i++) 
    {   
        for(int j=0;j<c;j++)
        {   
            is>>b[i][j].value;
            b[i][j].row=i+1;
            b[i][j].column=j+1;
        }
        while(dull != '\n'){dull = is.get();}
    }   

    is.close();
}

matrix matrix::operator+(const matrix& right)
{
    matrix rMatrix(right.getRows(),right.getColumns());

    if((r != right.r) || (c != right.c))
    {   
        return NULL;
    }

    rMatrix.r = r;
    rMatrix.c = c;

    //matrix addition algorithm
    for(int i=0;i<r;i++)
        for(int j=0;j<c;j++)    
        {   
            rMatrix.b[i][j].value = b[i][j].value+right.b[i][j].value;
            rMatrix.b[i][j].row = i+1;
            rMatrix.b[i][j].column = j+1;
        }

    return rMatrix;
}

matrix& matrix::operator=(const matrix& right)
{
    if(this == &right)
        return *this;

    for(int i=0; i<r;i++)
        delete [] b[i];
    delete b;

    r = right.getRows();
    c = right.getColumns();

    allocmem();
    for(int i=0;i<r;i++)
        for(int j=0;j<c;j++)
        {
            b[i][j].value = right.b[i][j].value; //RUN-TIME ERROR!
            b[i][j].column = j+1;
            b[i][j].row = i+1;
        }

    return *this;
}

int matrix::getColumns() const
{
    return c;
}
int matrix::getRows() const
{
    return r;
}

a.mt:

4 4
10.5 20.7 30.5 40.1
0 0 15.4 9.8
4 2 -8.3 4.2
9.3 2.7 1.2 8.9

b.mt:

4 4
-2.5 0.7 30.5 -54.1
0 1 0 9.8
4 7 8.3 4.2
7.3 2.7 -1.2 3.9

该程序应从文件中加载两个矩阵,然后计算它们的总和。实际上,它在深层复制方法(操作符=)内崩溃,抛出了这样的错误:enter image description here
我想问你哪里有bug,以及如何修复它。

2 个答案:

答案 0 :(得分:2)

尝试添加复制构造函数。

从运算符返回矩阵时,它使用复制构造函数初始化结果。默认值将按成员复制成员调用(包括指向数据的指针)。 然后释放内存,因为当您离开operator +时rMatrix被销毁,但是您尝试在上面的上下文中为operator =访问它。

答案 1 :(得分:1)

好吧,看来你不知道如何在C ++中处理动态内存。

这里没什么奇怪的,这是一个棘手的问题,所以你有2个解决方案:

  1. 不要操纵原始内存
  2. 了解如何操作原始内存
  3. 显然,从长远来看,学习如何操作原始内存更好......但短期解决方案是:

    std::vector<std::vector<field>> b;
    

    现在,让我们看看长期。

    1. 前言:除学习目的外,不要重新发明轮子
    2. 遵守单一责任原则:一个班级管理资源,或者它有业务功能,但不是两者都是
    3. 资源处理类必须遵守三条规则(仔细编写所有复制构造函数,复制赋值运算符和析构函数),并且必须特别注意处理这些方法中出现的异常
    4. 所以......我们走吧!一般架构将是:

      • 资源类,处理内存(以及所有内容)
      • 业务类,处理操作和依赖资源类

      先咬一点:

      // No reason to have line and column there, is it ?
      struct Field {
          Field(): value() {} // initialize value on construction, please!
      
          double value;
      };
      

      从资源类开始:

      // An array of N*M "Field" elements
      // It is minimalist, but minimalist is good!
      class FieldsArray {
      public:
          FieldsArray(size_t rows, size_t columns);
          FieldsArray(FieldsArray const& other);
          FieldsArray& operator=(FieldsArray const& other);
          ~FieldsArray();
      
          void swap(FieldsArray& other);
      
          Field& at(size_t i, size_t j);
          Field const& at(size_t i, size_t j) const;
      
      private:
          void allocate(); // rows & columns must be set
          void release();  // rows & columns must be set
      
          size_t rows;
          size_t columns;
          Field** fields;
      }; // class FieldsArray
      
      inline void swap(FieldsArray& left, FieldsArray& right) {
          left.swap(right);
      } // swap
      

      关于定义,我们意识到使用表格表是不方便的(使用一个大的N * M表会更容易)。

      FieldsArray::FieldsArray(size_t rows, size_t columns):
          rows(rows), columns(columns)
      {
          this->allocate();
      } // FieldsArray::FieldsArray
      
      FieldsArray::FieldsArray(FieldsArray const& other):
          rows(other.rows), columns(other.columns)
      {
          // Perform deep copy
          this->allocate();
      
          try {
              for (size_t i = 0; i < rows; ++i) {
                  for (size_t j = 0; j < columns; ++j) {
                      fields[i][j] = other.fields[i][j];
                  }
              }
          } catch(...) {
              this->release();
              throw; // rethrow
          }
      } // FieldsArray::FieldsArray
      
      FieldsArray& FieldsArray::operator=(FieldsArray const& other) {
          FieldsArray tmp(other);
          this->swap(tmp);
          return *tmp;
      } // FieldsArray::operator=
      
      FieldsArray::~FieldsArray() {
          this->release();
      } // FieldsArray::~FieldsArray
      
      void FieldsArray::swap(FieldsArray& other) {
          using std::swap;
          swap(this->rows, other.rows);
          swap(this->columns, other.columns);
          swap(this->fields, other.fields);
      } // FieldsArray::swap
      
      Field& FieldsArray::at(size_t i, size_t j) {
          assert(i < rows && "Wrong index!");
          assert(j < columns && "Wrong index!");
      
          return _fields[i][j];
      } // FieldsArray::at
      
      Field const& FieldsArray::at(size_t i, size_t j) const {
          assert(i < rows && "Wrong index!");
          assert(j < columns && "Wrong index!");
      
          return _fields[i][j];
      } // FieldsArray::at
      
      void FieldsArray::allocate(size_t rows, size_t columns) {
          fields = new Field*[rows];
      
          try {
              for (size_t i = 0; i < rows; ++i) { fields[i] = new Fields[columns]; }
          } catch(...) {
              this->release();
              throw; // rethrow
          }
      } // FieldsArray::allocate
      
      void FieldsArray::release() {
          for (size_t i = 0; i < rows; ++i) { delete[] fields[i]; }
          delete[] fields;
      } // FieldsArray::release
      

      是的,所有这些只是为了得到std::vector<Field>(大小为N * M)的等价物。我只是希望我没有弄乱它(注意:在C ++ 11中,std::unique_ptr<Field[]>会有很大的帮助...)

      现在,终于,我们开始致力于核心业务:

      class Matrix {
      public:
          Matrix(size_t rows, size_t columns): _data(rows, columns) {}
      
          Field& at(size_t i, size_t j) { return _data.at(i, j); }
          Field const& at(size_t i, size_t j) const { return _data.at(i, j); }
      
          Matrix& operator+=(Matrix const& other);
      
      private:
          FieldsArray _data;
      }; // class Matrix
      
      inline Matrix operator+(Matrix const& left, Matrix const& right) {
          Matrix result(left);
          result += right;
          return result;
      } // operator+
      

      operator+=的定义:

      Matrix& Matrix::operator+=(Matrix const& other) {
          assert(this->rows == other.rows && "Rows differ!");
          assert(this->columns == other.columns && "Columns differ!");
      
          for (size_t i = 0; i < rows; ++i) {
              for (size_t j = 0; j < columns; ++j) {
                  this->at(i, j) += other.at(i, j);
              }
          }
      
          return *this;
      } // Matrix::operator+=
      

      我会将其他方法的实施作为读者的练习;)