赋值运算符函数
赋值运算符是算是比较经常要重载的一个运算符,简单但也有许多细节需要注意
1.返回的类型声明为该类型的引用,目的为了支持连续赋值。例如:str1=str2=str3;
2.传入的参数类型声明为常量引用。声明为引用是为了提高效率,减少创建零时变量的开销,声明为常量则是防止传入的实例被修改。
所以参数应该声明为 const Class &;
3.释放自身已有的内存。这点尤其需要注意,如果类成员中有指针变量,那么就要考虑到动态内存分配。执行赋值操作时要先释放自身已有空间,然后重新申请空间赋值。否则将会出现内存泄漏。
4.判断传入参数和当前实例(*this)是不是同一实例。这也是存在动态内存分配情况下需要重点注意的一点。如果事先不进行判断,那么假如传入同一个实例将会释放自身内存,再也找不到需要赋值的内容了。
考虑以上几点得到如下代码:
class MyString { public: MyString(char* pData =NULL); MyString(const MyString& str); ~MyString(void); MyString& operator=(const MyString& str); private: char* m_pData; }; MyString& MyString::operator=(const MyString& str) { if( this == &str) return *this; delete[] m_pData; m_pData=NULL; m_pData = new char[strlen(str.m_pData)+1]; strcpy(m_pData,str.m_pData); return *this; }
还有一点需要考虑:new char 分配内存失败!!如果失败,因为我们在此之前已经释放原先的实例成员变量的内存,所以此时即使抛出异常处理我们也无法得到原先的实例,原先实例不再有效。
假如内存不足导致new char 分配内存失败了我们应该怎么办,上面代码没有做处理。
下面是一种简单的办法来实现赋值操作,同时提供了异常安全性:
MyString& MyString::operator=(const MyString& str) { if( this != &str) { MyString strtemp(str); char* ptemp = strtemp.m_pData; strtemp.m_pData = m_pData; m_pData = ptemp; } return *this; }
这里创建了一个临时变量实例,内存分配和释放就交给临时变量实例strtemp的构造函数和析构函数来处理。一旦创建成功就进行交换,所以析构的时候释放的就是原来的实例。如果内存不够创建临时变量失败那么就会抛出异常,此时还未改变原先实例,原先实例仍然有效。
ps:题外点,这里的copy构造函数传入的也是常量引用,假如不考虑效率问题,可以把引用去掉吗?当然不行!!会形成死循环哦。
学习笔记,如果各位有什么赐教的地方请不吝相赠!

浙公网安备 33010602011771号