使用动态分配和操作符重载的矩阵和
Sum of matrices using dynamic allocation and operator overloading
我写了一个代码,使用动态分配和操作符重载找到两个矩阵的和。
#include<iostream>
#include<new>
using namespace std;
class matrix
{
int**m;
int r;
int c;
public:
matrix(int a, int b)
{
r = a;
c = b;
m = new int*[r];
for (int i = 0; i < r; i++)
m[i] = new int[c];
}
~matrix()
{
for (int i = 0; i < r; i++)
delete[] m[i];
delete[] m;
}
friend istream &operator>>(istream &in, matrix s);
friend matrix operator+(matrix& m1, matrix& m2);
friend ostream &operator<<(ostream &out, matrix s);
};
istream &operator>>(istream &in, matrix s)
{
cout << "enter elements" << endl;
for (int i = 0; i < s.r; i++)
{
for (int j = 0; j < s.c; j++)
{
in >> s.m[i][j];
}
}
return in;
}
ostream &operator<<(ostream &out, matrix s)
{
for (int i = 0; i < s.r; i++)
{
cout << " ";
for (int j = 0; j < s.c; j++)
out << s.m[i][j] << " ";
cout << endl;
}
return out;
}
matrix operator+(matrix& m4, matrix& m5)
{
matrix m6(m4.r, m4.c);
for (int i = 0; i < m4.r; i++)
{
for (int j = 0; j < m4.c; j++)
{
m6.m[i][j] = m4.m[i][j] + m5.m[i][j]; //gets stuck here!
}
}
return m6;
}
int main()
{
int r, c;
cout << "enter number of rows and columns" << endl;
cin >> r >> c;
matrix m1(r, c), m2(r, c), m3(r, c);
cin >> m1;
cin >> m2;
m3 = m1 + m2;
cout << m3;
return 0;
}
当我执行时,我卡在了matrix operator+(matrix &m4,matrix &m5)
我在网上搜索,但我找不到我的错误。那么,我的代码出了什么问题?它在Code::Blocks中工作得很好,但在Xcode中不行。
我在你代码中看到的问题:
-
在构造函数中分配内存,在析构函数中释放内存。但是,您没有实现复制构造函数或复制赋值操作符。这会导致很多问题。
-
operator>>
的第二个参数需要是一个引用。否则,您将最终将数据读取到一个局部变量中。您用来调用它的对象不会有任何变化。没有实现复制构造函数的另一个不必要的副作用是,当该函数返回时,最终使用悬空指针,这是导致未定义行为的原因。
-
operator<<
的第二个参数应该是const&
。否则,您将不必要地创建对象的副本并删除它。由于缺少复制构造函数,该函数还会导致悬空指针。
复制构造函数可以实现为:
matrix(matrix const& copy) : r(copy.r), c(copy.c)
{
m = new int*[r];
for (int i = 0; i < r; i++)
{
m[i] = new int[c];
for (int j = 0; j < c; ++j )
{
m[i][j] = copy.m[i][j];
}
}
}
我将留给您实现复制赋值操作符
问题源于按值传递而不是按引用传递,但这暴露了完全缺乏三原则的遵从性。
R Sahu演示了复制构造函数来解决"三原则"问题。
我要走一条不同的路线:Die Array, Die !
与标准的愚蠢数组不同,std::vector符合三原则。在二维中使用它非常轻松:std::vector<std::vector<int>> mMatrix;
Vector使这个程序规则3/5兼容,这意味着您可以复制和移动矩阵对象,大大减少调试冒险。使用数组代替vector没有任何好处,除非数组的大小是固定的,所以在使用数组之前要仔细考虑。
注意名称的变化。matrix
已经被类使用了,所以稍微混淆一下名称就可以了。出于类似的原因,我做了更多的重命名:
size_t mRows; // can't have negative indexes, so why used a signed type?
size_t mCols;
构造函数现在看起来像这样:
matrix(size_t rows, size_t cols) :
mRows(rows), mCols(cols), mMatrix(rows, std::vector<int>(cols))
{
}
友元函数得到了轻微的修改,以获得更好的命名,并在需要的地方使用引用:
friend std::istream &operator>>(std::istream &in, matrix &out);
friend matrix operator+(matrix& rhs, matrix& lhs);
friend std::ostream &operator<<(std::ostream &out, matrix &in);
其余的基本可以保持不变。
但是有一个更好的方法:
#include<iostream>
#include<vector>
//using namespace std;
class matrix
{
size_t mRows; // can't have negative indexes, so why used a signed type?
size_t mCols;
std::vector<int> mMatrix;
// the vector is one dimensional, so tyhere is much less clean-up
// In addition, all of the data is contiguous and as cache-friendly as possible.
public:
matrix(size_t rows, size_t cols) :
mRows(rows), mCols(cols), mMatrix(rows * cols)
{
}
int & operator()(size_t row, size_t col)
{
if (row >= mRows || col >= mCols)
{ // trap bad indexing. discard if speed > safety.
throw std::out_of_range("Bad index");
}
return mMatrix[row * mCols + col]; // note the math
}
// returns a copy so the value can't be modified
int operator()(size_t row, size_t col) const
{
if (row >= mRows || col >= mCols)
{ // trap bad indexing. discard if speed > safety.
throw std::out_of_range("Bad index");
}
return mMatrix[row * mCols + col]; // note the math
}
friend std::istream &operator>>(std::istream &in, matrix &out);
friend matrix operator+(matrix& rhs, matrix& lhs);
friend std::ostream &operator<<(std::ostream &out, matrix &in);
};
这种布局更快,因为空间局部性有助于在工作时缓存数据。2d数组方法具有行数+1个不同的数组,这些数组可能位于RAM中非常不同的位置,这会导致缓存丢失和读取数据的时间增加,如果所有数据都在一个位置,则可能已经读取了数据。
- 重载操作符+:表达式必须是整型或无作用域枚举类型
- 重载操作符
- 如何重载操作符==外模板类使用友元函数
- 重载*操作符,使其在左右两边都工作
- 重载操作符<对于非随机迭代器
- 在c++中重载操作符的时间和原因
- 如何在c++中重载=操作符来通过引用进行复制
- 如何在c++中获取定义为友元的重载操作符的地址
- 使用重载操作符的文件操作表达式没有给出预期的结果
- 重载操作符()
- 重载操作符()并在类内使用
- 类中的重载操作符+
- 定时使用重载操作符
- c++带类的重载操作符
- 用列表容器重载[]操作符
- 重载操作符=
- 任何重载操作符()的静态检测
- 重载操作符以处理类对象
- 在使用另一个类的类中重载操作符==
- 派生类和基类中的重载操作符不同