如何来写好一个赋值运算符函数

来源:互联网 发布:液晶清洁液-知乎 编辑:程序博客网 时间:2024/06/06 16:47

如果面试官让你书写一个类的赋值运算符函数,他的考察点应该在:

  1. operator = 的返回值是否是一个reference to * this ,同时在函数的末尾是否返回了*this;为了支持连续的赋值,必须返回对象,否则例如a = b = c 这种语句无法通过编译。
  2. operator = 的参数是否是const reference。 reference避免了copy带来的消耗,例如调用形参的复制构造函数,提高代码效率。const则表明赋值号右边的操作数不会受到修改,这是良好编程风格的体现。
  3. 是否释放了对象自身的内存。如果我们忘记在释放已有内存之前为对象分配新内存,将造成内存泄漏。
  4. 是否处理好自身赋值问题。这一点是考察关键,我们详细说明。
  • 对象自身赋值可能会带来的问题。
    对象自身赋值本身是语法允许的,并不会带来什么问题。问题出现在赋值运算符的不规范书写上。考虑有下面这样一个赋值运算符:
class A{    public:    ...    A & operator =(const A & rsh)    {        delete ptr;        ptr = new B( * rsh.ptr );        return *this;    }    private :    B * ptr;}

这是没有考虑对象自我赋值的做法,结果将导致ptr指针指向不明。当发生对象自我赋值的时候,ptr与rsh.ptr所指的是同一块内存。在程序第一行,ptr所指内存已经被释放掉,第二行rsh.ptr也成为悬浮指针。

  • 解决办法
  1. 简单地加个认同测试
A &operator = (const A& rhs){    if(this==&rhs)    {        return *this;    }    delete ptr;    ptr = nullptr;    ptr = new B(* rhs.ptr );    return *this;   }

程序中发生自我赋值的情况并不多,然而每次进行对象赋值时都需要进行一次条件判断,效率较低,代码膨胀。

  1. 分配内存后再销毁
A &operator = (const A& rhs){       B * temp = ptr;       ptr = new B(* rhs.ptr);       delete temp;       return *this;}

这个解法的好处是万一new操作抛出了异常,ptr还是指向了原来的内存,而且这块内存的内容还没有被销毁。

  1. copy & swap 技术
    这种技术的思路是既然自我赋值会产生问题,那就创建一个新的变量来避免自我复制:
A & operator = (const A&rhs){    //copy    A temp(rhs);    //swap    swap(temp);//将this数据与temp数据进行交换    return *this;}

这种做法比较推荐,考虑到了异常安全性原则。

0 0
原创粉丝点击