开发者社区> 王小闹儿> 正文

Effective C++学习笔记

简介: 导读 本书的最佳用途:彻底了解C++如何行为,为什么那样行为,以及如何运用其行为形成优势。 size_t是一个typedef,是某种不带正负号的unsigned类型。
+关注继续查看

导读

本书的最佳用途:彻底了解C++如何行为,为什么那样行为,以及如何运用其行为形成优势。


size_t是一个typedef,是某种不带正负号的unsigned类型。

签名(signature):函数的参数和返回值。即std::size_t num(int number) 的签名是 std::size_t  ( int )

explicit可组织他被用来隐式转换(implicit type conversions),但他仍可以被进行显示转换(explicit type conversions)。

如图:

拷贝构造---以同型对象初始化自我对象。

拷贝赋值---从另一个同性对象中拷贝其值到自我对象。




1、让自己习惯C++

条款一:视C++为一个语言联邦

c++是四种语言的联邦


每种语言都有自己的规约。C++高效编程守则视状况而变化,取决于你使用C++的哪一部分。


条款2:尽量以const、enum、inline替换#define

也就是“宁可以编译器替换预处理”。因为define或许不被视为语言的一部分。



class专属常量:为了将常量的作用域(scope)限制于class内,必须让它成为class的一个成员(member);而为了确保此常量最多只有一份实体,必须让它成为static成员。

我们无法用#define创建一个专属常量。



menu hack:

1、menu hack的行为更像#define,而不是const。例如取const地址是合法的,而取menu hack或者#define的地址是不合法的。

2、如果不希望别人活得一个pointer或reference指向你的某个常量,enum可以帮你实现这个约束。

3、enum和#define绝不会导致没必要的内存分配,因为有的编译器会为const对象设定另外的存储空间。

4、enum hack是模板元编程的技术基础。


对于单纯的常量,最好以const对象或enum替换#define;对于形似函数的宏,最好用inline函数替换#define。



条款3:尽可能使用const



令函数的返回值为const,可以降低因客户错误而造成的意外。如下图:

class R{.....}
const R poerator *(const R& lns, const R& rhs)


两个成员函数如果只是常量性(constness)方面不同,可以被重载,如下图:


上图中non-const operator[]的返回值类型是char &,而不是char,因为如果函数的返回类型是一个内置类型,那么改动函数返回值就不合法(what?我不懂。。。吴老师:这个说法有点令人困惑。关键不是内置类型与否,而是值类型与否。需要修改内容,函数需要返回一个非const的引用。。。还是不太懂。。。)




条款4:确定对象被使用前已先被初始化

int x;

c++语言中,上述语句在某些语境下,x被初始化为0,某些情况下x不被初始化。读取未初始化的值会导致不明确的行为。在某些平台上,仅仅只是读取未初始化的值,就可以让你的程序终止运行。


不要混淆赋值和初始化,如下图:


c++规定:对象成员变量的初始化动作发生在进入构造函数本体之前。

使用初始列进行初始化的效率更高,因为比起先调用default构造函数然后再调用copy assignment操作符,单只调用一次copy构造函数比较高效,有时甚至高效得多。

(1) 在初始化列表中,成员的初始化顺序和成员的声明顺序相同,与初始化列表的位置顺序无关。 
(2) 初始化列表先于构造函数执行。 

(3) 类中可以定义const成员变量,它并非真正意义的常量,而是只读变量,其初始化方式只能依靠初始化列表。

const只读变量虽然不可出现在赋值符号的左边,但是可以通过指针去修改其值的。(what???)

当你想要default构造一个成员变量,你都可以使用初值列,只要指定无物(nothing)作为初始化实参即可。如下图:


规定总是在初值列中列出所有成员变量,以免去记忆哪些成员变量可以无需初值。

如果成员变量是const或references,它就需要初值,而不能被赋值。具体原因详见链接:

https://blog.csdn.net/qq_29344757/article/details/76093216

在class 中,变量不能直接初始话,需要通过构造函数(或拷贝构造函数)来初始话,如果程序员没有定义构造函数系统会有一个默认构造函数。

除了静态数据成员外,数据成员不能在类体内显式的初始化




不同编译单元内定义之non-local static 对象







条款5:了解C++默默编写并调用哪些函数

当你写一个空类没有声明的时候,编译器会为他声明一个copy构造函数、一个copy assignment函数和一个析构函数。如果你没有声明任何构造函数,编译器会为你声明一个default构造函数。如下图:


当这些函数被调用的时候,编译器才会把他们创建出来。

注意:编译器产生的析构函数是一个non-virtual,除非这个class的base class自身声明有virtual析构函数(不明觉厉,先记下来)

如果类中你声明了一个带实参的构造函数,编译器便不会创建default构造函数,如此,你写的构造函数就不会被创建出来的无实参的default构造函数覆盖掉。






条款6:若不想使用编译器自动生成的函数,就应该明确的拒绝




驳回编译器自动提供的功能,可将相应的成员函数声明为private并且不予实现。或者使用上图所示的手法也可以(上图所示的手法感觉更好一点)



条款7:为多态基类声明virtual析构函数



如果一个类里面不含虚函数,通常意味着他并不意图被用做一个base class(基类)。当类不企图被当做base class,灵其析构函数为virtual往往是个馊主意。C++标准库中很多都是没有虚函数的class,比如string、vector、list等,所以不要把标准库中的类作为基类。

虚指针vptr(virtual table pointer)用于在运行期决定哪一个虚函数被调用。vptr指向一个由函数指针构成的数组,该数组称为虚表vtbl(virtual table):每个带有虚函数的类都有对应的虚表。

纯虚函数导致抽象类(不能被实例化(instantiated)的类)

虚析构函数的作用为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。(用C++开发的时候,用来做基类的类的析构函数是虚函数。

Class ClxBase
{
public:
    ClxBase() {};
    //虚虚构函数
    virtual ~ClxBase() {};

    virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
};


条款8:别让异常逃离析构函数

析构函数绝对不要吐出异常。如果一个被析构函数调用的函数可能会抛出异常,析构函数应该捕捉任何异常,然后吞下他们(不传播)或结束程序。

如果客户需要对某一操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。


条款9:绝不在构造和析构过程中调用虚函数

class Transation {
public:
	Transation();
	virtual void logTransaction() const = 0;
	...
};

Transation::Transation() {
	...
	logTransaction();//构造函数调用虚函数
}

class BuyTransation :public Transation {
public:
	virtual void logTransation() const;
	...
};
上述代码执行:
BuyTransation b;

在该调用logTransaction时,调用的虚函数是base class中的,而不是BuyTransaction中的。

因为:base class(基类)构造期间,虚函数不会下降到derived classes(子类)阶层。由于base classes构造函数的执行更早于的derived classes构造函数,当base class 构造函数执行时derived class的成员变量尚未初始化,如果器件调用的virtual函数下降至derived classes阶层,而derived classes的函数机会必然去用local成员变量,而那些成员变量尚未初始化,因此无法调用derived classes中的虚函数,而是调用base class的虚函数。

更根本原因:在derived class对象的base class 构造期间,对象的类型是base class而不是derived class。不止虚函数会被编译器解析至base class,若使用运行期类型信息,也会把对象是为base class。

logTransaction是纯虚函数,除非他被定义,否则程序无法连接,因为连接器找不到必要的Transaction::logTransaction实现代码。

弥补措施:在构造期间,可以藉由“令derived classes将必要的构造信息向上传递至base class构造函数”。



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

赋值采用右结合定律,因此x=y=z=15等价于(x=(y=(z=15)))。为了实现“连锁赋值”,赋值操作符必须返回一个reference指向操作符的左侧实参。




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

“自我赋值”发生在对象被赋值给自己时。拷贝构造函数里面应该先判断一下传入的参数是不是自己。



条款12:复制对象时勿忘其每一个成分

如果你自己写拷贝构造函数,而不用编译器默认构造的拷贝构造函数,当你为class添加一个成员变量后,你必须同时修改拷贝构造函数,如果你忘记,编译器也不太可能会提醒你。一旦你给这个class添加了子类,而忘记修改基类的拷贝构造函数,子类就无法对从父类那里继承下来的变量进行赋值。

拷贝构造函数应该确保复制“对象内的所有成员变量”及“所有base class成分”。


不要试图使拷贝赋值函数调用拷贝构造函数,同时也不要试图让拷贝构造函数调用拷贝赋值函数。如果上述两个函数有重复代码,可以在private里面写一个函数供上述两个函数调用,该函数常备命名为init



条款13:对象管理资源


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
大数据中 TopK 问题的常用套路
对于海量数据的处理经常会涉及到 topK 问题。在设计数据结构和算法的时候,主要需要考虑的应该是当前算法(包括数据结构)跟给定情境(比如数据量级、数据类型)的适配程度,和当前问题最核心的瓶颈(如降低时间复杂度,还是降低空间复杂度)是什么。
6 0
iOS-底层原理 15:dyld发展史
iOS-底层原理 15:dyld发展史
6 0
最近这个 GitHub 项目,增长有点猛
今天给大家分享一个 GitHub 刷题项目,也是目前我们 Doocs 成员们在积极维护的一个项目。
5 0
一文看懂开源图化框架中的循环设计逻辑!
相信大家在日常工作中,已经精通各种循环逻辑的实现。就拿我来说吧,多年的工作经验,已经让我可以熟练的使用 C++,Python,英语等多种语言,循环多次输出“hello word”。不过大家有没有想过一个这样的问题:如何在一个有向无环图(Directed Acyclic Graph,简称dag)中实现循环呢?
5 0
手撸一款简单高效的线程池(一)
线程池大家应该都用过,不过如何从 0 到 1 的设计一款简单好用且性能较好的线程池?我们在接下来的几篇文章中,为您一一介绍。
4 0
手撸一款简单高效的线程池(二)
大家好,我是不会写代码的纯序员——Chunel Feng[1]。这篇文章是线程池优化系列连载的第二篇。主要跟大家介绍几种线程池优化思路,包括:local-thread 机制、lock-free 机制、work-stealing 机制。
6 0
手撸一款简单高效的线程池(三)—— 性能优化!
在上一章中,我们给大家介绍了一些 C++线程池中的优化思路和实现方案。这一章中,我们将继续这个主题,接着聊线程池中还有可以“压榨”的空间。为实现我们吹过的牛 B,而继续编程
5 0
手撸一款简单高效的线程池(四)
在前几章的内容中,我们给大家介绍了一些 C++线程池中的优化思路和实现方案。这一章中,我们来聊一聊在编程实现过程中,一些工程层面的优化。让我们的代码执行的速度,跟得上自己的思路。
4 0
手撸一款简单高效的线程池(五)
在之前的内容中,我们给大家介绍了 C++实现线程池过程中的一些常用线优化方案,并分析了不同机制使用时的利弊。这一篇,是线程池系列的最后一章。我们会介绍一下 CGraph 中的 threadpool 如何使用,给出性能对比,并对接下来的工作做一些展望。让我们在线程池性能优化和功能提升的道路上,越走越远。
5 0
心中有“树”!图文并茂介绍数据结构中常见的树(一)
提到数据结构中的树(Tree) ,大家应该都不陌生,相关书籍中都有大段篇幅的介绍,刷 Leetcode 的时候会遇到很多相关问题。很多人往往会用 “手写红黑树” 来形容面试难度很高。
10 0
+关注
王小闹儿
应届c++
129
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载