2012年3月4日星期日

C++拷贝构造函数一记

C++拷贝构造函数一记
     -- 一个困扰小李的程序问题

背景说明:
     某日,小李同事(以前KS老同事)在Q群里喊了一个程序问题……正好当时我没啥事就关注关注,了解并跟进了问题……结果,帮忙调到了出现问题地方。话说这种问题虽然不算高深,但是比较微妙可能很多C++程序猿都曾类似地犯错过。鉴于这一点,所以我就在此小小博文一篇,谨此提醒C++朋友们少犯类似的错误吧。

问题描述:
     Debug版本程序必崩,而Release版本运行正常。程序崩溃在main函数语句mat2 = (mat+mat1);

问题原因:
     程序没有定义Matrix类型的拷贝构造函数,在调用函数operator+之后,其返回值Matrix对象析构了指针mat指向的数据,而导致函数外部使用其返回值无效,这样使得Debug版程序崩溃;而为什么函数Release版程序运行正常呢,原因在于程序经编译器优化,使得函数operator+返回值Matrix对象与函数外使用的属于同一对象,即不析构函数operator+内的局部变量,让其对象继续在函数外使用,这样程序运行就正常了。具体的细节设计C++对象模型,相关的详细知识参见《C++对象模型》。

解决方案:
     正确定义Matrix类型的拷贝构造函数。详见如下红色代码。

红色标记表示(添加)修改部分!

-- Matrix.h --
#include <iostream>
#include <cassert>

using namespace std;

template <class T>
class Matrix
{
private:
    int col;
    int row;
    T **mat;
public:
    Matrix() {}
    Matrix(int col,int row);
    virtual ~Matrix();

    Matrix(const Matrix<T>& obj)
        :col(obj.GetCol()), row(obj.GetRow())
    {
        assert (col >=0 && row >=0);
        if (col && row)
        {
            mat=new T*[row];
            for(int i=0; i<row; i++)
            {
                mat[i]=new T[col];
                for (int j=0; j < col; ++j)
                {
                    //mat[i][j] = (obj.getValue(i, j));
                    mat[i][j] = obj[i][j];
                }
            }
        }
    }

public://矩阵操作
    T* operator[] (int index) const
    {
        return mat[index];
    }
    T getValue(int r, int c) const
    {
        return mat[r][c];
    }

    int GetCol()const;
    int GetRow()const;
public://运算符重载
    //一般运算符重载
    Matrix& operator=(const Matrix<T>& matrix);
    //二元运算符重载
    template <class T>
    friend Matrix<T> operator+(const Matrix<T>& left, const Matrix<T>& right);
    Matrix operator-(const Matrix<T>& matrix);
public://数据获取
    void GetData(const char* fileName);
    void PrintMat();
private://工具函数

};
template <class T>
Matrix<T>::Matrix(int row,int col )
{
    this->col=col;
    this->row=row;
    mat=new T*[row];
    for(int i=0; i<row; i++)
    {
        mat[i]=new T[col];
    }
}
template <class T>
Matrix<T>::~Matrix()
{
    for(int i=0; i<row; i++)
        delete [] mat[i];
    delete [] mat;
}
template <class T>
int Matrix<T>::GetCol()const
{
    return this->col;
}
template <class T>
int Matrix<T>::GetRow()const
{
    return this->row;
}
template <class T>
void Matrix<T>::PrintMat()
{
    for(int i=0; i<this->row; i++)
    {
        for(int j=0; j<this->col; j++)
        {
            cout << mat[i][j] << "  ";
        }
        cout <<  endl;
    }
}
template <class T>
void Matrix<T>::GetData(const char* fileName)
{
    ifstream fileIn(fileName);
    if(!fileIn)
    {
        cout << "Read Error!" << endl;
        return;
    }
    for(int i=0; i<row; i++)
    {
        for(int j=0; j<col; j++)
        {
            fileIn >> mat[i][j];
        }
    }
    fileIn.close();
}

template<class T>
Matrix<T>& Matrix<T>::operator=(const Matrix<T>& matrix)
{
    if (this == &matrix)
        return *this;

    this->col=matrix.col;
    this->row=matrix.row;
    for(int i=0; i<row; i++)
    {
        for(int j=0; j<col; j++)
        {
            this->mat[i][j]=matrix.mat[i][j];
        }
    }
    return *this;
}

template<class T>
Matrix<T> operator+(const Matrix<T>& left, const Matrix<T>& right)
{
    Matrix<T> tmp(left.col, left.row);
    for(int i=0; i<left.row; i++)
    {
        for(int j=0; j<left.col; j++)
        {
            tmp.mat[i][j]=left.mat[i][j]+right.mat[i][j];
        }
    }
    return tmp;
}
template<class T>
Matrix<T> Matrix<T>::operator-(const Matrix<T>& matrix)
{
    if(this->col!=matrix.col||
            this->row!=matrix.row)
    {
        cout << "Can not add the matrixs!" << endl;
    }

    Matrix<T> tmp(this->col, this->row);
    for(int i=0; i<this->row; i++)
    {
        for(int j=0; j<this->col; j++)
        {
            this->mat[i][j]=this->mat[i][j]-matrix.mat[i][j];
        }
    }
    return tmp;
}
#endif


-- main.cpp --

#include "matrix.h"
int main(void)
{
    Matrix<int> mat(3,3);
    mat.GetData("SourceData.txt");
    mat.PrintMat();
    Matrix<int> mat1(3,3);
    mat1.GetData("SourceData.txt");
    mat1.PrintMat();
    Matrix<int> mat2(3,3);
    mat2 = (mat+mat1);
    mat2.PrintMat();
    std::cout << "hello world.\n";
    return 1;
}

没有评论:

发表评论