在学习关系运算符重载的时候,看见重载函数中的函数参数使用的是引用类型,于是在思考为什么需要用引用,而不是非引用,例如:
引用格式:bool operator==(Person & p)
非引用格式:bool operator==(Person p)
思考这个问题?
条件:Person对象中存在new的成员属性
思考这个问题之前,先看一下学习关系运算符重载的代码:
class Person { public: //年龄的指针,初始化是用new来创建的,放在堆区,因此需要注意深浅拷贝问题 int *m_Age; Person(int age){ m_Age = new int(age); } Person& operator=(Person &p){ // 如果m_Age在堆中占内存,则需要delete堆中的内存 if (m_Age != NULL){ delete m_Age; m_Age = NULL; } m_Age = new int(*p.m_Age); return *this; } ~Person(){ // 如果m_Age还在堆中占内存,则需要delete if (m_Age != NULL){ delete m_Age; m_Age = NULL; } cout << "析构函数" << endl; } bool operator==(Person& p){ if (*this->m_Age == *p.m_Age){ return true; } return false; } // 这里必须函数的参数必须使用引用,否则会报错! // 因为如果不使用引用的话,则会使用浅拷贝,导致析构的时候出错函数 bool operator!=(Person& p){ if (*this->m_Age != *p.m_Age){ return true; } return false; } }; void test01() { Person p1(18); Person p2(20); Person p3(30); p3 = p2 = p1; //赋值操作 cout << "p1的年龄为:" << *p1.m_Age << endl; cout << "p2的年龄为:" << *p2.m_Age << endl; cout << "p3的年龄为:" << *p3.m_Age << endl; // 如果重载==时,不使用引用,则会delete p2中new的m_Age cout << boolalpha << (p3 == p2) << endl; //此时p2的m_Age为NULL cout << *p2.m_Age << endl; cout << &p1.m_Age << " " << &p2.m_Age << " " << &p3.m_Age << endl; cout << boolalpha << (p2 != p3) << endl; cout << "再次结束" << endl; //而且我还发现,析构函数的顺序,恰好与创建对象的顺序相反! } int main() { test01(); //int a = 10; //int b = 20; //int c = 30; //c = b = a; //cout << "a = " << a << endl; //cout << "b = " << b << endl; //cout << "c = " << c << endl; return 0; }
上述代码是没问题的
于是回到最开始的思考,如果把重载运算符函数的参数变为非引用格式会是什么结果呢?
Text(686,0x10aaef600) malloc: *** error for object 0x600002068050: pointer being freed was not allocated Text(686,0x10aaef600) malloc: *** set a breakpoint in malloc_error_break to debug
直接报错,显示被释放的指针没有被分配内存
因此考虑,为什么报错呢?
思考过程:
1、释放指针是什么意思?在Person中只有m_Age是需要自己手动释放的,那问题肯定是出在这里!
2、为什么释放的指针没有被分配内存?于是开始排查主函数中是p1,p2,p3中谁的m_Age被释放了?通过在析构函数中打印发现原来是真的是重载函数出的问题!
3、开始思考为什么使用引用参数没事,非引用参数就会被释放?
浅拷贝和深拷贝问题!
使用非引用参数的话,在调用函数的时候会创建一个临时浅拷贝的临时对象,在函数执行结束之后会析构掉这个临时的对象,由于浅拷贝因此会把之前p1或p2或p3中的m_Age析构掉,因此问题就出现在这里!
如果使用的是引用,则不会出现创建临时对象浅拷贝的问题!
问题到这就算是解决了!
但是我还在思考,为什么使用引用就不会呢?是因为引用是对象的别名,函数调用完之后只是会删除别名所占的空间,由于原来对象的生命周期还没结束,因此不会被删除?这么理解是否正确呢?还是有更好的理解方式呢?
换个角度思考,引用也就是指针变量,那么? 明白了!因为引用本身根本就没有创建新的对象,因此不会删除对象的内存!
而且还发现
创建对象的顺序是p1、p2、p3
析构函数的顺序是p3、p2、p1
总结:
- 在针对对象中含有new的成员变量,需要特别注意!
- 如果有new的成员变量,注意函数是否会创建临时对象
- 创建的对象是深拷贝还是浅拷贝
按照上述三点考虑应该就能很好处理这次遇到的问题。
标签:函数参数,Age,运算符,Person,引用,重载,拷贝 From: https://www.cnblogs.com/henabo/p/16718797.html