引例
在进行对象的相互赋值的时候会出现成员逐一赋值初始化(Memberwise initialization),但是对于指针来说,成员逐一赋值会导致不同的对象寻址到同一内存区域,导致析构时的混乱
代码测试
main.cpp
#include "Matrix.h"
int main()
{
Matrix mat(4,4);
{
Matrix mat2=mat;
Matrix mat3;
mat3(mat);
}
mat.成员函数();
return 0;
}
matrix.h
#include<iostream>
using namespace std;
class Matrix{
public:
Matrix(int row,int col)
:_row(row),_col(col)
{
_pmat=new double[row*col];
}
// Matrix(const Matrix& rhs);
~Matrix()
{
//自由空间的释放
delete [] _pmat;
cout<<"destructor"<<endl;
}
private:
int _row,_col;
double* _pmat;
};
上面的mat.成员函数()调用会出错,因为在mat2代码块的析构函数已经将_pmat释放了,所以我们有两种解决方法
- 添加下面的copy constructor
Matrix::Matrix(const Matrix &rhs)
:_row(rhs._row),_col(rhs._col)
{
int elem_cnt=_row*_col;
_pmat=new double[elem_cnt];
cout<<"copy constructor"<<endl;
for(int ix=0;ix<elem_cnt;++ix)
_pmat[ix]=rhs._pmat[ix];
}
- 添加copy assignment operator
Matrix& Matrix::
operator=(const Matrix &rhs)
{
if(this !=&rhs)
{
_row=rhs._row;_col=rhs._col;
int elem_cnt=_row*_col;
delete [] _pmat;
_pmat=new double[elem_cnt];
for(int ix=0;ix<elem_cnt;++ix)
_pmat[ix]=rhs._pmat[ix];
}
return *this;
}
感悟心得
在设计class时,必须问自己,在此clas之上进行"成员逐一初始化"是否合适,是否需要添加copy constructor,我在这里认为只要有地址之类的data member就需要copy constructor.
其实这里涉及到的就是我们常说的浅拷贝与深拷贝的问题:
浅拷贝:两个变量进行浅拷贝时,它们指向同一个地址,它们的值相同。这样会有问题,当其中的一个析构了那个地址,另外一个也没有了,有时候会发生错误,但浅拷贝比较廉价。
深拷贝:两个变量进行深拷贝时,第二变量会重新申请一块区域来存放跟第一个变量指向地址的值。两个东西完全是独立的,只是值相同。消耗比较大,因为要重新申请空间。
触发拷贝构造函数:如果我们没有定义拷贝构造函数,系统会默认给我们定义拷贝构造函数,只不过这种拷贝构造函数是浅拷贝,会出现问题。在一个方法以对象作为参数传进去或者一个方法中以对象作为返回都会调用拷贝构造函数,但是如果返回与参数传递采用的是reference形式,则不会调用拷贝构造函数。