移动构造函数 - C++ 模板类的运算符重载

 手机用户2502873453_987 发布于 2022-11-05 14:09

自己写了一个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);

这里有两次复制构造,一次复制赋值, 本应该是移动构造的,太奇怪了。还有很多问题,大都与这有关。这是怎么回事呢?

1 个回答
  • 我跑了一下(加了两行cout),matrix<double> eee(aaa + bbb);对应的输出是,

    Default Constructor
    Copy Add

    不是

    Copy Constructor
    Copy Assignment
    Copy Constructor
    Free done

    所以,没有“两次复制构造,一次复制赋值”,而是“一次默认构造,一次矩阵加法”,也即以下代码:

    template <typename T>
    matrix<T> matrix<T>:: operator + (matrix<T> &c){
        // ...
        matrix<T> temp(c.row(),c.col());
        // ...
        cout << "Copy Add" << endl;
        return temp;
    }
    

    所以问题是,为什么矩阵加法返回了临时变量(右值引用),但eee却没有调用移动构造函数?
    我认为,这里是编译器进行了更古老的一个处理——返回值优化,把矩阵加法的返回值直接构造在了eee上,省去了temp
    “典型地,当一个函数返回一个对象实例,一个临时对象将被创建并通过复制构造函数把目标对象复制给这个临时对象。C++标准允许省略这些复制构造函数,即使这导致程序的不同行为,即使编译器把两个对象视作同一个具有副作用。”——引自前述返回值优化维基百科
    至于为什么返回值优化会优先于移动构造函数执行,我不知道原因。我能提供的信息是,返回值优化在C++98(1998年)里已经有了,移动构造(右值引用)在C++11(2011年)里才有。

    2022-11-10 04:56 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有