自己写了一个matrix的模板类, 但是在重载运算符时,出现问题了。
下面是matrix类:
// matrix.h -- A simple matrix class; #ifndef __MATRIX_H_ #define __MATRIX_H_ #include #include #include #include #include #include #include #include using namespace std; template class matrix { private: vector> data; public: matrix(int nRow = 2, int nCol = 2){ data.resize(nRow); for (int i = 0; i < nRow; i++) { data[i].resize(nCol); } cout << "Default Constructor" << endl; } matrix(matrix & c):data(c.data){ data = c.data; cout << "Copy Constructor" << endl; } matrix(matrix &&c):data(std::move(c.data)){ cout << "Move Constructor" << endl; } matrix operator = (matrix &c); matrix operator = (matrix &&c){ data = move(c.data); cout << "Move Assignment" << endl; return *this; } int row(){ return data.size();} // Get row of the matrix. int col(){ return (row() ? data[0].size() : 0);} // Get col of the matrix. bool is_empty(){return (row() == 0);} // check if the matrix is empty. bool is_square(){return (!is_empty()) && (row() == col());} // check if the matrix is a square matrix. void resize(int nrow, int ncol); // Resize matrix void display(); // print matrix. T &operator()(int i, int j){ if ((i < 0) || (i >= row())||(j < 0)||(j >=col())) { cerr << "(" << i << "," << j << ") Out of Range" << endl; exit(1); } return data[i][j]; } matrix operator + (matrix &c); matrix operator - (matrix &c); matrix operator * (matrix &c); matrix operator / (matrix &c); matrix operator += (matrix &c); matrix operator -= (matrix &c); matrix operator *= (matrix &c); matrix operator /= (matrix &c); matrix operator + (matrix &&c); matrix operator - (matrix &&c); matrix operator * (matrix &&c); matrix operator / (matrix &&c); matrix operator += (matrix &&c); matrix operator -= (matrix &&c); matrix operator *= (matrix &&c); matrix operator /= (matrix &&c); template friend std::ostream &operator<< (std::ostream &out, matrix &c); ~matrix(){ cout << "Free done" << endl; } }; template matrix matrix:: operator = (matrix &c){ if (this == &c) { return *this; } if( row() != c.row()){ int nrow = row();data.resize(c.row()); if ((row() < c.row()) && (col() != c.col())) { for (int i = 0; i < c.row(); i++) { data[i].resize(c.col()); } } if ((row() < c.row()) && (col() == c.col())) { for (int i = row(); i < c.row(); i++) { data[i].resize(c.col()); } } } for (int i = 0; i < c.row(); i++) { for (int j = 0; j < c.col(); j++) { data[i][j] = c.data[i][j]; } } cout << "Copy Assignment" << endl; return *this; } template void matrix:: resize(int nrow, int ncol){ if ((row() == nrow) && (col() == ncol)) { return; } if ((row() == nrow) && (col() != ncol)) { for (int i = 0; i < nrow; i++) { data[i].resize(ncol); } } if ((row() != nrow) && (col() == ncol)) { data.resize(nrow); if (row() < nrow) { for (int i = row(); i < nrow; i++) { data[i].resize(ncol); } } } if ((row() != nrow) && (col() != ncol)) { data.resize(nrow); for (int i = 0; i < nrow; i++) { data[i].resize(ncol); } } } template void matrix:: display(){ cout << "Row = " << row() << "\tCol = " << col() << endl; cout.precision(10); for (int i = 0; i < row(); i++) { for (int j = 0; j < col(); j++) { cout << setw(8) << data[i][j] << " "; } cout << endl; } } template matrix matrix:: operator + (matrix &c){ if ((row() != c.row()) || (col() != c.col())) { cerr << "Dimensions of matrices besides + don't match! Exit!!!" << endl; exit(-1); } matrix temp(c.row(),c.col()); for (int i = 0; i < c.row(); i++) { for (int j = 0; j < c.col(); j++) { temp(i,j) = data[i][j] + c(i,j); } } cout << "Copy Add" << endl; return temp; } template matrix matrix:: operator + (matrix &&c){ if ((row() != c.row()) || (col() != c.col())) { cerr << "Dimensions of matrices besides + don't match! Exit!!!" << endl; exit(-1); } // matrix temp(c.row(),c.col()); for (int i = 0; i < c.row(); i++) { for (int j = 0; j < c.col(); j++) { c(i,j) += data[i][j]; } } cout << "Move Add" << endl; return c; } template matrix matrix:: operator - (matrix &c){ if ((row() != c.row()) || (col() != c.col())) { cerr << "Dimensions of matrices besides + don't match! Exit!!!" << endl; exit(-1); } matrix temp(row(),col()); for (int i = 0; i < row(); i++) { for (int j = 0; j < col(); j++) { temp(i,j) = data[i][j] - c(i,j); } } return temp; } template matrix matrix:: operator - (matrix &&c){ if ((row() != c.row()) || (col() != c.col())) { cerr << "Dimensions of matrices besides + don't match! Exit!!!" << endl; exit(-1); } for (int i = 0; i < row(); i++) { for (int j = 0; j < col(); j++) { c(i,j) = data[i][j] - c(i,j); } } return c; } template std::ostream &operator << (std::ostream &out, matrix &c){ if(c.is_empty()){ return out; } for (int i = 0; i < c.row(); i++) { for (int j = 0; j < c.col(); j++) { out << setw(8) << c(i,j) << " "; } out << endl; } return out; } #endif /* __MATRIX_H_ */
但在调用时,
#include #include "matrix.h" using namespace std; int main(int argc, const char *argv[]) { matrix my(3,3); my(2,2) = 2.12; cout << my; cout << endl << endl; matrix aaa(my); cout << endl << endl; matrix bbb(my); cout << endl << endl; bbb = aaa + my + bbb; cout << endl << endl; matrix ccc = aaa + my + bbb; cout << endl << endl << endl; matrix ddd=aaa; ddd = bbb; cout << endl << endl; matrix eee(aaa + bbb); cout << endl << endl; return 0; }
结果却是这样:
Default Constructor 0 0 0 0 0 0 0 0 2.12 Copy Constructor Copy Constructor Default Constructor Copy Add Default Constructor Copy Add Move Assignment Copy Constructor Free done Free done Free done Default Constructor Copy Add Default Constructor Copy Add Free done Copy Constructor Copy Assignment Copy Constructor Free done Default Constructor Copy Add Free done Free done Free done Free done Free done Free done
移动构造函数并没有执行,
matrix eee(aaa + bbb);
这里有两次复制构造,一次复制赋值, 本应该是移动构造的,太奇怪了。还有很多问题,大都与这有关。这是怎么回事呢?
我跑了一下(加了两行cout),
matrix eee(aaa + bbb);
对应的输出是,Default Constructor
Copy Add
不是
Copy Constructor
Copy Assignment
Copy Constructor
Free done
所以,没有“两次复制构造,一次复制赋值”,而是“一次默认构造,一次矩阵加法”,也即以下代码:
所以问题是,为什么矩阵加法返回了临时变量(右值引用),但
eee
却没有调用移动构造函数?我认为,这里是编译器进行了更古老的一个处理——返回值优化,把矩阵加法的返回值直接构造在了
eee
上,省去了temp
。“典型地,当一个函数返回一个对象实例,一个临时对象将被创建并通过复制构造函数把目标对象复制给这个临时对象。C++标准允许省略这些复制构造函数,即使这导致程序的不同行为,即使编译器把两个对象视作同一个具有副作用。”——引自前述返回值优化维基百科
至于为什么返回值优化会优先于移动构造函数执行,我不知道原因。我能提供的信息是,返回值优化在C++98(1998年)里已经有了,移动构造(右值引用)在C++11(2011年)里才有。