关系运算符重载,以及在关系运算符重载发现的函数参数什么时候需要用引用

在学习关系运算符重载的时候,看见重载函数中的函数参数使用的是引用类型,于是在思考为什么需要用引用,而不是非引用,例如:

引用格式: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的成员变量,注意函数是否会创建临时对象

- 创建的对象是深拷贝还是浅拷贝

 

按照上述三点考虑应该就能很好处理这次遇到的问题。

posted @ 2022-09-22 12:07  何侠客  阅读(163)  评论(0编辑  收藏  举报