从方法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
该程序应从文件中加载两个矩阵,然后计算它们的总和。实际上,它在深层复制方法(操作符=
)内崩溃,抛出了这样的错误:。
我想问你哪里有bug,以及如何修复它。
答案 0 :(得分:2)
尝试添加复制构造函数。
从运算符返回矩阵时,它使用复制构造函数初始化结果。默认值将按成员复制成员调用(包括指向数据的指针)。 然后释放内存,因为当您离开operator +时rMatrix被销毁,但是您尝试在上面的上下文中为operator =访问它。
答案 1 :(得分:1)
好吧,看来你不知道如何在C ++中处理动态内存。
这里没什么奇怪的,这是一个棘手的问题,所以你有2个解决方案:
显然,从长远来看,学习如何操作原始内存更好......但短期解决方案是:
std::vector<std::vector<field>> b;
现在,让我们看看长期。
所以......我们走吧!一般架构将是:
先咬一点:
// 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+=
我会将其他方法的实施作为读者的练习;)