自己写了一个matrix的模板类, 但是在重载运算符时,出现问题了。
下面是matrix类:
// matrix.h -- A simple matrix class;
#ifndef __MATRIX_H_
#define __MATRIX_H_
#include <iostream>
#include <ostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <iomanip>
using namespace std;
template <typename T>
class matrix {
private:
vector<vector<T>> 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<T> & c):data(c.data){
data = c.data;
cout << "Copy Constructor" << endl;
}
matrix(matrix<T> &&c):data(std::move(c.data)){
cout << "Move Constructor" << endl; }
matrix<T> operator = (matrix<T> &c);
matrix<T> operator = (matrix<T> &&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<T> operator + (matrix<T> &c);
matrix<T> operator - (matrix<T> &c);
matrix<T> operator * (matrix<T> &c);
matrix<T> operator / (matrix<T> &c);
matrix<T> operator += (matrix<T> &c);
matrix<T> operator -= (matrix<T> &c);
matrix<T> operator *= (matrix<T> &c);
matrix<T> operator /= (matrix<T> &c);
matrix<T> operator + (matrix<T> &&c);
matrix<T> operator - (matrix<T> &&c);
matrix<T> operator * (matrix<T> &&c);
matrix<T> operator / (matrix<T> &&c);
matrix<T> operator += (matrix<T> &&c);
matrix<T> operator -= (matrix<T> &&c);
matrix<T> operator *= (matrix<T> &&c);
matrix<T> operator /= (matrix<T> &&c);
template<typename U> friend std::ostream &operator<< (std::ostream &out, matrix<T> &c);
~matrix(){
cout << "Free done" << endl;
}
};
template <typename T>
matrix<T> matrix<T>:: operator = (matrix<T> &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 <typename T>
void matrix<T>:: 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 <typename T>
void matrix<T>:: 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 <typename T>
matrix<T> matrix<T>:: operator + (matrix<T> &c){
if ((row() != c.row()) || (col() != c.col())) {
cerr << "Dimensions of matrices besides + don't match! Exit!!!" << endl;
exit(-1);
}
matrix<T> 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 <typename T>
matrix<T> matrix<T>:: operator + (matrix<T> &&c){
if ((row() != c.row()) || (col() != c.col())) {
cerr << "Dimensions of matrices besides + don't match! Exit!!!" << endl;
exit(-1);
}
// matrix<T> 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 <typename T>
matrix<T> matrix<T>:: operator - (matrix<T> &c){
if ((row() != c.row()) || (col() != c.col())) {
cerr << "Dimensions of matrices besides + don't match! Exit!!!" << endl;
exit(-1);
}
matrix<T> 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 <typename T>
matrix<T> matrix<T>:: operator - (matrix<T> &&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 <typename T>
std::ostream &operator << (std::ostream &out, matrix<T> &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 <iostream>
#include "matrix.h"
using namespace std;
int main(int argc, const char *argv[]) {
matrix<double> my(3,3);
my(2,2) = 2.12;
cout << my;
cout << endl << endl;
matrix<double> aaa(my);
cout << endl << endl;
matrix<double> bbb(my);
cout << endl << endl;
bbb = aaa + my + bbb;
cout << endl << endl;
matrix<double> ccc = aaa + my + bbb;
cout << endl << endl << endl;
matrix<double> ddd=aaa;
ddd = bbb;
cout << endl << endl;
matrix<double> 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<double> eee(aaa + bbb);
这里有两次复制构造,一次复制赋值, 本应该是移动构造的,太奇怪了。还有很多问题,大都与这有关。这是怎么回事呢?
I ran it (added two lines of cout), the corresponding output of
matrix<double> eee(aaa + bbb);
is,Default Constructor
Copy Add
No
Copy Constructor
Copy Assignment
Copy Constructor
Free done
So, there is no "two copy constructions, one copy assignment", but "one default construction, one matrix addition", that is, the following code:
So the question is, why does matrix addition return a temporary variable (rvalue reference), but
eee
doesn't call the move constructor?I think this is an older process performed by the compiler - return value optimization, which constructs the return value of matrix addition directly on
eee
, omittingtemp
."Typically, when a function returns an object instance, a temporary object is created and the target object is copied to the temporary object via a copy constructor. The C++ standard allows these copy constructors to be omitted, even if this results in different behavior of the program. It has side effects that the compiler treats two objects as the same.”——Quoted from the aforementioned return value optimization Wikipedia
. As for why return value optimization takes precedence over move constructors, I don't know the reason. The information I can provide is that return value optimization is already available in C++98 (1998), and move construction (rvalue reference) is only available in C++11 (2011).