Effective c++学习笔记(item10 item11)

2021-10-11  本文已影响0人  懒生活

Effective c++学习笔记(item10 item11)

item10 是最简单的一节,item11和item10完全可以归并成一章。
实际上Scott通过item10 和item11 告诉了我们拷贝赋值函数的标准实现。包括拷贝复制函数的返回约定,和是否是自我赋值的保护限定。同时在item11中描述了另一种copy and swap的技术用于实现拷贝复制。

1 为什么拷贝赋值函数在重载时限定要返回自身类的引用类型?

这是因为操作符=的常用场景决定的,我们经常有类似的赋值语句a=b=c=11,这个语句在执行时先执行c=11然后把(c=11)的返回值(操作符=的返回值)继续赋值给b,以此类推。如果操作符=返回是空,那么就满足不了这种连续赋值的使用场景。所以赋值操作符不光要实现对象的内部赋值,还要返回一个可以用于连续赋值的数据。这个数据约定俗成是*this。只是约定,你硬要返回int,编译也能通过,但是那样是不推荐的。对于操作符=, +=, -=, *=, /=都有上述的约定,他们的操作符重载模板如下

class TTT
{
                TTT& operator=(const TTT& rhs)
                {
                                ...
           return *this;
                }
};

2重载拷贝复制操作符的时候需要判断是否是自我赋值

所谓自我赋值就是a=a的语句。当拷贝赋值涉及资源和指针的时候,自我赋值极其容易出现资源的操作错误。
观察如下的代码有可能出现的问题

class Widget
{
                private:
                                Bitmap* pb;
}
Widget& Widget::operator=(const Widget& rhs)
{
                delete pb;
     pb = rhs->pb;
     return *this;
}

当这个操作符重载函数作用于自己的时候,第一句话是释放自己指针指向的位置,第二句话是把自己指针给自己(但指针已经被无意间释放掉了),这样子返回的*this里面带了一个野指针。
为了解决这个问题,通常要添加一个证同测试

class Widget
{
                private:
                                Bitmap* pb;
}
Widget& Widget::operator=(const Widget& rhs)
{
                if(this == &rhs) return *this; 
                delete pb;
     pb = rhs->pb;
     return *this;
}

3 指针拷贝操作的"异常安全性"

观察下面两个代码实现

Widget& Widget::operator=(const Widget& rhs)
{ 
                delete pb;
     pb = fun(rhs->pb);
     return *this;
}
Widget& Widget::operator=(const Widget& rhs)
{ 
                Bitmap* pbbak = pb;
             pb = fun(rhs->pb);
                delete pbbak;
     return *this;
}

从原则上要坚持使用第二段代码的使用顺序,就是对指针先赋值,确保赋值成功后再delete。在第二段代码中如果执行到pb=fun(rhs->pb)中发出了异常,那么pb没有被赋值,同时因为异常也不会删除。 不像第一段代码先被删除,后赋值。那么赋值的时候如果发生了异常导致pb成为野指针。

4 copy and swap技术

这个后面单独章节描述

上一篇 下一篇

猜你喜欢

热点阅读