《More Effective C++》总结笔记(一)——基础议题、操作符

基础议题

条款1:仔细区别pointers和references

  • 首先你必须认知一点,没有所谓的 null reference。
  • 由于reference一定得代表某个对象,C++因此要求references必须有初值。
  • Pointers和references之间的另一个重要差异就是,pointers可以被重新赋值,指向另一个对象,reference却总是指向(代表)它最初获得的那个对象。
  • 结论:当你知道你需要指向某个东西,而且绝不会改变指向其他东西,或是当你实现一个操作符而其语法需求无法由pointers达成,你就应该选择references。任何其他时候,请采用pointers。

条款2:最好使用C++转型操作符

  • C++提供的4种新的转型操作符,相比于C风格的转型,尽管其语法看起来又臭又长。但它提供了严谨的意义以及更强的辨识度。
  • 如果你在程序中使用新式转型法,比较容易被解析(不论是对人类还是对工具而言),编译器也因此得以诊断转型错误(那是旧式转型法侦测不到的)。
  • 让转型动作既丑陋又不易键入(typing),或许未尝不是件好事。

条款3:绝对不要以多态方式处理数组

  • 因为基类和派生类大小不一样,函数传参时如果是形参是基类数组,实参是派生类的数组,这时在函数内循环遍历基类数组的结果就是不可预期的。
  • 简单地说,多态和指针算术不能混用。数组对象几乎总是会涉及指针的算术运算,所以数组和多态不要混用。

条款4:非必要不提供default constructor

class EquipmentPiece {
public:
  EquipmentPiece(int IDNumber = UNSPECIFIED);
  ...
private:
  static const int UNSPECIFIED;  //一个某数数字,意味没有被指定ID值。
};
  • 这就是一个添加了default constructor的class,这样我们就可以直接通过
    EquipmentPiece e;
    这样的语句来产生一个EquipmentPiece的object。虽然方便了使用,但是这几乎总是会造成class内的其他member functions变得复杂。
  • 添加无意义的default constructor,会影响classes的效率。如果member functions必须测试字段(指的是default constructor被赋了默认值的必备字段)是否真的被初始化了,其调用者便必须为测试行为付出时间代价,并为测试代码付出空间代价,因为可执行文件和程序库都变大了。万一测试结果为否定,对应的处理又需要一些空间代价。如果class constructors可以确保对象的所有字段都被正确地初始化,上述所有成本便都可以免除。如果default constructor无法提供这种保证,那么最好避免让default constructor出现。虽然这可能会对classes的使用方式带来某种限制,但同时也带来一些保证:当你真的使用了这样的classes,你可以预期它们所产生的对象会被完全地初始化,实际上亦富有效率。

操作符

条款5:对定制的“类型转换函数”保持警觉

  • 单自变量constructors和隐式类型转换操作符可以让自定义类型实参隐式转换。
  • 重载类型转换操作符可能会导致错误(非预期)的函数被调用。解决办法就是以功能对等的另一个函数取代重载的类型转换操作符(参考std::string的c_str)。
  • 将constructors声明为explicit,使得编译器不能因隐式转换的需要而调用它们,只能显示的调用。通过这种方式可以消除单自变量constructors引起的隐式转换。

条款6:区别increment/decrement操作符的前置和后置形式

  • 重载increment前置式和后置式操作符的范式(decrement同理):
// 前置式:累加然后取出(increment and fetch)
UPInt& UPInt::operator++()
{
*this +=1;
return *this;
}
// 后置式:取出然后累加(fetch and increment)
const UPInt UPInt::operator++(int)
{
UPInt oldValue = *this;
++(*this);
return oldValue;
}
  • 为了使类似i++++这样的调用不合法,所以重载后置式increment操作符的返回值必须是const的。
  • 后置式increment和decrement操作符的实现应以其前置式兄弟为基础。如此一来你就只需维护前置式版本。
  • 因后置式increment(decrement)函数会返回一个临时对象,所以它天生效率没有其前置式兄弟高(主要对自定义类型)。

条款7:千万不要重载&&,||和,操作符

  • C++对于“真假值表达式”采用所谓的“骤死式”评估方式。意思是一旦该表达式的真假值确定,即使表达式中还有部分尚未检验,整个评估工作仍告结束。
  • 而如果重载了&&或||操作符则他们变成了函数调用,函数调用则没办法实现类似的“骤死式”语法,因为函数调用必须所有参数都评估完成。而且也无法保证表达式的评估顺序,因为C++语言规范并未明确定义函数调用动作中各参数的评估顺序。
  • 逗号操作符也有类似问题。表达式如果内含逗号,那么逗号左侧会先被评估,然后逗号的右侧再被评估;最后,整个逗号表达式的结果以逗号右侧的值为代表。而如果重载它,无法模仿这些行为。

条款8:了解各种不同意义的new和delete

  • 如果你希望将对象产生于heap,请使用new operator。它不但分配内存而且为该对象调用一个constructor。如果你只是打算分配内存,请调用operator new,那就没有任何constructor会被调用。如果你打算在heap objects产生时自己决定内存分配方式,请写一个自己的operator new,并使用new operator,它将会自动调用你所写的operator new。如果你打算在已分配(并拥有指针)的内存中构造对象,请使用placement new。
  • 总结关系如下:
new <->delete
operator new <-> operator delete //分配、释放内存
placement new <-> placement delete //在指定内存上构造、析构对象
new[] <-> delete[]
  • operator new调用示范:
void *rawMemroy = operator new(sizeof(string));
  • plcement new示范:
class Widget {
public:
  Widget(int widgetSize);
  ...
};
Widget* constructWidgetInBuffer(void* buffer, int widgetSize)
{
  return new (buffer) Widget(widgetSize);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容