effective c++ (四)

条款10:令operator=返回一个reference to *this

为了实现“连锁赋值”,赋值操作符必须返回一个reference指向操作符的左侧实参,这是你为classes实现赋值操作符时应该遵循的协议。

class Widget{
public:
      ...
      Widget& operator+=(const Widget& rhs)   //同样适用于-=, *=
      {
              ...
              return *this;
      }

      Widget& operator=(const Widget& rhs)   //同样适用于-=, *=
      {
              ...
              return *this;
      }

      Widget& operator=(int rhs)   //此函数也是和,即使此一操作符参数类型不符合协定
      {
              ...
              return *this;
      }
};

注意,这只是一个协议,并无强制性。如不遵循它,代码一样可以通过编译。然而这份协议被所有内置类型和标准程序库提供的类型工作遵守(string vector  complex tr1::shared_ptr)

请记住:

  • 令赋值操作符(assignment)操作符返回一个reference to *this

条款11:在operator=中处理“自我赋值”

1、一般而言,如果某段代码操作pointers或references而它们被用来“指向多个相同类型”,就需要考虑这些对象是否为同一个。实际上,两个对象只要来自同一个继承体系,甚至不需要声明为相同类型就可能造成“别名”(应为base class的指针或引用可以指向一个derived)。如:

a[i] = a[j] //若i与j具有相同的值,这便是自我赋值;

*px = *py//如果px与py恰巧指向同一个对象,则时自我赋值

void doSomething(const Base& rb, Derived* pd);//若rb与rp可能指向同一个对象

2、如果遵循条款13和14的忠告,你会运用对象来管理资源,而且你可以确定所谓“资源管理对象”在copy发生时有正确的举措。在这种情况下你的赋值操作符或许是“自我赋值安全的”(self-assignment-safe),不需要额外操心

3、如下代码,在自我赋值时会会抛出异常

class Bitmap { ... };
class Widget
{
      ...
private:
   Bitmap* pb;
};

Widget& Widget::Operator=(const Widget& rhs)
{
    delete pb;
    pb = new Bitmap(*rhs.pb);
   return *this;
}

这里若是自我复制问题是,operator=函数内的*this和rhs有可能是同一对象;若是如此delete就不只是销毁当前对象的bitmap,也销毁了rhs的bitmap

Widget& Widget::operator=(const Widget& rhs)
{
     if(this == &rhs) return *this;
     delete pb;
     pb = new Bitmap(*rhs.pb);
     return *this;
}

如此在赋值前进行一个“认同测试(identify test)”达到自我赋值的检验目的

但是此段代码不具备“异常安全性”,在new Bitmap导致异常(不论是因为分配时内存不足或因为Bitmap的copy构造函数抛出异常),Widget最终会持有一个指针指向一块被删除的Bitmap。

时间: 2024-11-09 03:32:05

effective c++ (四)的相关文章

《Effective C#》快速笔记(四)- 使用框架

.NET 是一个类库,你了解的越多,自己需要编写的代码就越少. 目录 三十.使用重写而不是事件处理函数 三十一.使用 IComparable<T> 和 IComparer<T> 实现顺序关系 三十二.避免使用 ICloneable 接口 三十三.仅用 new 修饰符处理基类更新 三十四.避免重载基类中定义的方法 三十五.PLINQ 如何实现并行算法 三十六.理解 PLINQ 在 I/O 密集场景 三十七.注意并行算法中的异常 三十.使用重写而不是事件处理函数 1.处理系统之中触发的

《Effective C++》重点摘要(四)

<Effective C++>第四章:设计与声明 让接口容易被正确使用,不易被误用.一个接口由返回类型.接口名称.和参数列表组成,为了让接口容易被正确的使用,需要小心设计返回类型,最好是简单.直接.自然.接口名称选择很重要,做到简单.达意.无歧义.参数列表形参类型需要身份小心,如果能防范非法输入,尽力为之,形参名也尽可能做到同接口名称一样的标准.另外请保持命名习惯的一致性也能收到奇效. 设计class犹如设计type.用户对语言内置的type支持的行为一般十分熟悉,所以最好自行设计的class

Effective C++ 条款四 确定对象被使用前已被初始化

1.对于某些array不保证其内容被初始化,而vector(来自STL)却有此保证. 2.永远在使用对象前初始化.对于无任何成员的内置类型,必须手工完成.      int x = 0;      const int * p = &x; 3.不要混淆赋值与初始化的区别.一般初始化在定义的时候一起进行.而赋值是在定义之后的动作.      比如说在某一个类中的构造函数中,函数的行为都是赋值操作,而非初始化操作.      一般来说,对象的成员变量的初始化动作发生在进入构造函数本体之前.所以,我们一

《Effective C#》:区别和认识四个判等函数

.Net有四个判等函数?不少人看到这个标题,会对此感到怀疑.事实上确是如此,.Net提供了ReferenceEquals.静态Equals,具体类型的Equals以及==操作符这四个判等函数.但是这四个函数之间有细微的关系,改变其中一个函数的实现会影响到其他函数的操作结果. 首先要说的是Object.ReferenceEquals和Object.Equals这两个静态函数,对于它们俩来说,是不需要进行重写的,因为它们已经完成它们所要得做的操作. 对于Object.ReferenceEquals这

Effective Objective-C 2.0 — 第四条:多用类型常量,少用#define预处理指令

第四条:多用类型常量,少用#define预处理指令 使用#define 预处理的坏处:定义出来的常量没有类型信息,编译器只是会在编译前据此执行查找与替换操作.即使有人重新定义了常量值,编译器也不会产生警告信息,这将导致应用程序中的常量值不一致. 使用例如:static const NSTimeInterval kAnimationDuration = 0.3; 在实现文件中使用 static const 来定义“只在编译单元内可见的常量”.由于此类常量不再全局符号表中,所以无须为其名称加前缀.

《Effective C++》学习笔记(四)

原创文章,转载请注明出处:http://blog.csdn.net/sfh366958228/article/details/38845319 前言 今天给自己订的任务是将<Effective C++>第二章看完,一口气看下来发现量并不大,这一章剩下的内容都较为简短,来看看今天的条款吧. 条款08:别让异常逃离析构函数 如同条款的字面意思,不要让析构函数中抛出异常,这样会使程序出现不明确行为. 举个例子:有一个Widget的自定义类的vector. vector<Widget> v

Effective JavaScript :第四章

1.理解:prototype.getPrototypeOf和_proto_之间的不同 ①C.prototype用于建立new C()创建的对象的原型. ②Object.getPrototypeOf(obj)是ES5中用来获取obj对象的原型对象的标准方法. ③obj._proto_是获取obj对象的原型对象的非标准方法. 类的本质上是一个构造函数与一个用于在该类实例间共享方法的原型对象的结合.   2.使用闭包存储私有数据 JavaScript的对象所有的属性名都是一个字符串,任意一段程序都可以

Effective Java2读书笔记-创建和销毁对象(四)

第7条:避免使用终结方法 这一条讲的简直是不知所云.先简单记下来其中说出的几条: ①显式终止方法的典型例子有InputStream.OutputStream和java.sql.Connection上的close方法,以及java.util.Timer上的cancel方法.这些方法一般与try-catch连用,在finally中调用显式的终止方法.终结方法的意义在于这些close方法忘记调用时,充当安全网的作用(感觉扯淡,close都会忘,终结方法能记得?). ②finalize方法,源自Obje

[读书笔记]Effective Java 第四章

使类和成员的可访问性最小化 规则很简单:尽可能地使每个类或者成员不被外界访问.实例域(非final)决不能是公有的.当需要暴露出不可变的实例时通常会把这个实例做成不可变或者是把这个实例变成私有,同时提供该实例的备份. 在公有类中使用访问方法而非公有域 这就是常说的getter和setter方法,提供给包外访问时提供必要的方法,限制客户端的行为,以便于将来可以在内部改变表示方法. 使可变性最小化 不可变的类比可变类更加易于设计.实现和使用.它们不容易出错,且更加安全.为了使类成为不可变,要遵循下面

Effective Java2读书笔记-类和接口(四)

第19条:接口只用于定义类型 这一条就举了一个反例,说有些接口中只包含常量.这是对接口的不良使用.要实现相同的功能,应该使用不可实例化的工具类(第4条说过). public class PhysicalConstants { private PhysicalConstants() { } // Prevents instantiation // Avogadro's number (1/mol) public static final double AVOGADROS_NUMBER = 6.02