重载赋值号的问题?为什么不能自赋值
#include <iostream>
#include <string.h>
#include <cstring>
using namespace std;
class A
{
public:
char *ptr;
void set_ptr(char *str)
{
ptr = new char[strlen(str) + 1];
strcpy(ptr, str);
}
A &operator=(const A &rhs)
{
cout << "rhs.ptr1: " << rhs.ptr << endl;
this->ptr = new char[strlen(rhs.ptr) + 1];
cout << "rhs.ptr: " << rhs.ptr << endl;
cout << "this->ptr:" << this->ptr << endl;
return *this;
}
};
int main()
{
A a;
char *name = (char *)"hello world";
a.set_ptr(name);
a = a;
// 等效于a.operator=(a);
cout <<"a.ptr2: "<<a.ptr<<endl;
}
运行结果如下:
rhs.ptr1: hello world
rhs.ptr:
this->ptr:
a.ptr2:
分析一下程序:
这是一个赋值号的重载函数,功能是:对象能直接赋值另一个对象。这个重载运算符的函数并不完整,只为说明问题。
这里是自赋值,即a对象赋值给a对象。 但我们可以发现, 在执行 this-> ptr = new char[strlen(rhs.ptr) + 1]; 之前。rhs.ptr的值是 hello world
而执行完 this-> ptr = new char[strlen(rhs.ptr) + 1]; 之后再次执行 cout << "rhs.ptr: " << rhs.ptr << endl; 打印rhs.ptr 发现结果是空,
执行cout << “this->ptr:” << this->ptr << endl;,this .ptr也是空。但我并没有主动调用delete去释放空间。原因就是指针改变了指向,导致指针指向了未知的新的空间,而新的空间没有任何东西
this->ptr = new char[strlen(rhs.ptr) + 1]; 翻译一下
new一块和rhs.str大小一样的空间,然后返回一个变了的地址给this.str,也就是说a.str的地址变了,rhs是a的引用,不是指针,所以rhs.str自然也就是a.str,也改变了。也就是重置了指针指向。
另一种情况如下:
另一个更重要的原因是保证正确性。一个赋值运算符必须首先释放掉一个对象的资源(去掉旧值),然后根据新值分配新的资源。在自己给自己赋值的情况下,释放旧的资源将是灾难性的,因为在分配新的资源时会需要旧的资源。
如下面的代码:
#include<iostream>
#include<string>
#include<string.h>
using namespace std;
class A
{
public:
char *ptr;
A(){ptr = nullptr;}
void set_ptr(char *str){ptr = new char[strlen(str)+1]; strcpy(ptr,str);}
A& operator=(const A&rhs)
{
delete this->ptr;
this->ptr = new char[strlen(rhs.ptr)+1];
strcpy(this->ptr,rhs.ptr);
return *this;
}
};
int main()
{
A a;
char*name=(char*)"hello world";
a.set_ptr(name);
a = a;
cout<<a.ptr<<endl;
}
执行完delete this->ptr;之后,rhs.ptr 的指向就悬空了。对此我们有两种解决方法:
下面有几种办法
1、判断参数是否是自身
那么就要重载==或者!=运算符
if(*this != rhs)
该运算符不止要判断数据成员的值是否相等
还要判断ptr的指向(即ptr的指针值是否相等)
那么这样的运算符失去了一般性(没必要判断ptr的指针值是否相等,而是判断指向的内容是否相等)
所以简化的方法就是 if (this == &m_point) // 不能if(*thism_point)因为同地址必然同值,但同值不一定同地址,除非按上述的所说的重载
if (this == &m_point) // 不能if(*this==m_point)因为同地址必然同值,但同值不一定同地址
return *this;
str = new char[strlen(m_point.str) + 1];
strcpy(str, m_point.str);
return *this;
delete[] str;//防止内存泄漏
2.2、即先将右操作数的内容赋值到一个临时指针
然后释放左操作数指针指向的内存
然后将临时指针赋给左操作数的指针
class A
{
public:
char *ptr;
A(){ptr = nullptr;}
void set_ptr(char *str){ptr = new char[strlen(str)+1]; strcpy(ptr,str);}
A& operator=(const A&rhs)
{
char *temp = new char[strlen(rhs.ptr)+1];//复制资源到一个临时指针
strcpy(temp,rhs.ptr);
delete ptr;
ptr = temp;
return *this;
}
};