随手笔记之Effective C++

以下是 Effective C++读后总结,虽不完整但看完这些也就差不多相当于看完Effective C++了。

 

条款02: 尽量以const enum inline 代替 #define.

#define 定义的宏 ,在编译的时候之前预处理全部替换掉,这样存在一个问题,例如:#define ABC 100 你在编译的过程中又用到ABC ,但是此时ABC 并没用添加到记号表中,出现编译错误,还有如果这个宏是其他文件中的,你对于这个100的来源开始估计也是莫名其妙的,所以尽量替代#define,

Const 定义的常量是要分配内存的,并且定义的时候要赋值。你可以取这个变量的地址,

Enum :枚举类型可以充当一个ints 使用,例如 enum{NUM = 5};  int a[NUM];

这是可行的,还有就是,enum 取地址是不合法的,通常取#define 地址也是不合法的.

由于宏定义会存在较多的隐患,比如自增自减, 那么这种情况最好用inline函数来是实现.

 

条款03: 尽量多用const

Const 可以定义常量,可以定义常指针等,C++中的迭代器 const_iterator  指明迭代器指向的内容是常量,如果迭代器为常指针,那么可以 const xxx.iterator it = xxx;

Const 的成员函数,是用来不让改变某个对象中的值,例如 常对象,只能调用const 的成员函数,防止改变。

如果const 和 non-const 实现的代码是一样的,那么可以再non-const 中调用const 

这个函数,以减少代码量,但要进行转化, 第一添加Const 的这个转换 为了安全,static_cast ,后面去除const 这个特性,const_cast:

 

条款04:

1. 内置内型对象手工初始化。

2. 构造函数最好使用成员初值列表,而不要在构造函数中使用赋值,这样第一是效率方面,因为构造函数中赋值,是首先调用其他类类型的默认构造函数,然后在赋值,而初始化列表中,是直接进行一个copy 的构造函数,效率相对于快,但是对于内置内型的话没多大的差别,初始化的顺序最好相同,

3. 为了避免“跨编译单元的初始化次序,用local static 来替换 non-local static对象”.

 

条款05:构造、析构、赋值运算

当你定义一个空类的时候,那么编译器其实是默认会有一个默认的构造函数,一个默认的拷贝构造函数,一个默认的赋值操作符,一个默认的析构函数,,他们都是默认的public 并且inline 。

如果你的成员数据是引用类型的,那么赋值操作符是不行的,因为引用时不允许修改的,那么这个时候就要我们自己去写一个赋值操作符的函数,如果一个基类的赋值操作符为私有的,那么编译器是不会为基于这个基类的派生类生成一个赋值操作符,因为为派生类生成一个赋值操作符本身是想处理基类中的成分,但是因为是私有的所以无权调用。

 

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

当你不想一个类能够进行一个拷贝构造或者一个赋值操作符时候,那么我们可以定义这个拷贝构造和赋值操作符函数为私有类型,就可以了,相对于说还是比较不错的选择,那么这也有一个问题,如果你定义了一个friend 函数,这是会破坏封装的一种用法,他可以访问私有的数据,所以我们聪明的话不去定义friend,或者定义一个基类实现,然后继承这个基类,那么这个时候如果你是friend调用这个派生类的拷贝或者赋值,派生类中的会去尝试调用基类的,所以是行不通的。

 

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

一般基类中有一个或者一个以上的virtual 函数的时候,定义析构函数为virtual ,因为如果有的时候派生类中有分配的空间,如new 分配的一段空间,假如基类中没有virtual 析构函数,那么析构的时候,由于是给了基类的指针,那么调用的是基类中的析构函数,派生类的析构函数并没有调用,所以说这样可能就会导致内存的一些泄露等情况,加上virtual 这个关键字的析构函数,会首先调用派生类中的析构函数,然后在调用基类中的析构函数。

 

条款08:不要让异常逃离析构函数

如果假如一个客户连接了数据库,要求close退出的时候,但是客户可能忘记了,我们要在析构函数的时候去捕捉这个异常,

如果抛出异常就结束程序,可以通过调用abort 完成。

吞下异常,可以用try  catch 

析构函数不要吐出异常,如果一个析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下或者结束程序。

 

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

为了实现“连锁赋值” 赋值操作符必须返回一个reference 指向操作符的左侧实参,如:int & operator +=(const int &rhs)

{  return  *this;}

 

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

例如: int & A::operator =(const A & rhs)

{

If(this == rhs) return *this;

Delete mm;

Mm= new .....

Return *this;

 

}

这里是提前判断一下。

 

条款12:复制对象时候不要忘记复制每一个成分

1. Copy 函数应该确保复制”对象内的所有成员变量“及”所有base class 成分”

2.不要尝试以某个copy 函数去调用另一个copy 函数 应该将共同机能放进第三个函数中,并由两个copy 函数共同调用。

 

条款18: 让接口容易被正确的使用,不易被误用.

例如我创建一个日期类,其中的构造函数要填写的参数,用户使用可能会输入顺序错误,或者超过界限,所以我们用定义一个接口的使用要小心使用,我们比较好的方法是把月,年,日,全部用类封装起来,这样我们可以放心一点使用,

Std::tr1::shared_ptr 智能指针,可以帮用户省很多事情,它的引用次数为0 会调用“删除器”,消除了客户的内存泄露问题,另外还有一个消除了潜在的客户问题:“cross-DLL probllem”,这个问题发生在“对象在动态链接程序库中被new,却在另外一个DLL中delete”,智能指针会追踪这个记录,引用的次数来决定调用的是哪个DLL的delete.

 

条款20:宁以pass-by-reference-to-const  替换pass-by-value

例如参数的时候如果是类,那么以传值的方式就会产生构造析构的一些动作,如果是引用的方式不必要,并且在引用的时候我们前面加上一个const,这样防止去改变传进来的东东,这样效率就提高很多,并且容易被接受,

Slicing 切割的问题。解决方案是by_reference-to-const

切割的问题是:例如一个基类win,定义了一个mywin 是继承它,那么通过一个函数传进去的参数,参数的类型是基类类型,那么我们直接用传值方式的话这样会产生切割问题,调用的肯定是基类的方法,所以避免产生用引用的方式。

所谓的切割就是把派生类的一些自有的特性给除去了,因为是传值,这样构造的对象肯定就是基类的对像。

内置类型一般采用的是传值方式,

 

条款21:返回对象时,不要一味的返回其reference.

绝对不要返回指针或者引用局部变量,或者返回reference 指向局部堆对象,或者返回指针或者引用局部静态对象。

局部堆由于是new了,必然要delete,谁来?没有办法取得引用后面的指针,所以会导致内存泄露,

静态的局部变量虽然可以,但是会造成多线程的困恼。

 

条款22:将成员变量声明为private.

成员数据应该最好private ,这更能体现封装性。

 

条款23:宁以non-member  non-friend 替换member 函数

面向对象的要求是,数据以及操作数据的那些函数应该绑在一起,意味着member 函数是较好的选择,但是这个建议是不正确的,这是基于对面向对象的真实的一个误解,面向对象的守则是要求数据应该尽可能的被封装,但是许多方面non_member 函数做法要比member 做法好,我们了解下原因:

1. Non-member , non-friend 较大的封装性是它并不增加“能够访问”类中的private成分。

2. 命名空间的好处作用是各个功能可以独立,命名空间可以跨多个文件,但是类不行,例如,list,vector 等,我们用到只要包含头文件就可以,他们都是在命名空间std 下实现的。

 

条款24: 若所有参数皆需类型的转换,请为此采用non-member 函数。

Explicit 一般作用于构造函数,防止“隐式转换”,如果不加的时候,可以隐式转换不会出错,如果加上则必须是要某种类的类型,否则出错。也就是说

1、explicit主要用于 "修饰 "构造函数. 

2、使得它不用于程序中需要通过此构造函数进行 "隐式 "转换的情况! 

3、指定此关键字,需要隐式转换方可进行的程序将会不能通过. 而可通过强制转换 使它没有用. 

例如 乘法,本身要求是类与类相乘,但是如果你写成类*一个整形数,那么这个整形数会隐式转换成这个类的类型,就是用这个整形编译器去调用构造函数构造一个对象,加上explicit 则会出错,但是如果写成一个整形数*一个类,那么则是必然出错,因为 整形数不会调用类中的成员函数,它会在整个全局中找看有没有符合这个类型的操作函数像,operator(int, 类),这样,发现也没有,那么就认定错误,所以这种存在隐式转换,我们就用non-member 函数。 

但是我们会讨论要不要定义为friend 函数,否定的,因为这个函数完全可以由pubic 接口函数去完成。

 

条款26:尽可能延后变量定义式的出现时间

可以改善程序的效率和代码的清晰,有时候我们定义的变量可能没用到或者还没有用的时候出现了异常而导致没有用到,这样假如是类类型的话,就浪费了构造和析构的时间。

 

条款27:尽量少做转型动作

C++提供四种转型动作

1. Const_cast<T>  目的是去除常量的特性。也是唯一的一个转型操作符。

2. Dynamic_cast<T> 主要执行“安全向下转型”,决定某对象是否归属于继承体系中的某个类型。

3. Reinterpret_cast<T> 执行低级的转型。

4. Static_cast<T> 用来强迫隐式转换,唯一不能是将const 转换为non-c】onst 。

优良的C++代码很少使用转型,但是不能说完全不使用,例如一个除法int x/int y

这时候将x转换为 double 是很好的。

如果转型是必要的,那么最好是将其隐藏在某个函数的背后,客户随后可以调用该函数,而不需要将转型放进他们自己的代码内。

 

条款28:避免返回handles 指向对象内部成分。

和之前提到过的一样,避免返回引用局部的变量或者局部的指针。

 

条款29:为“异常安全”而努力是值得的。

异常是在你不知情的情况下发生,如果没有相应的异常处理函数来处理,可能会出现严重的错误,异常函数的作用是:

1. 不要泄露任何资源。例如互斥锁,你后面分配空间,万一失败,你最后的释放锁永远不会执行,

2. 不允许数据败坏。你new空间,之前你删除了一个指针指向的东西,但是万一new失败,那么这个本来是想指向new 的,但是失败,之前的东西又被删除了,这样是错误的。可以用资源管理类来解决内存泄露的问题。

3. 基本的承诺,如果抛出异常,程序中的任何事物保持在有效的状态下,没有任何的的数据或结构遭到破坏。

4. 强烈保证。如果抛出异常,程序状态不改变,函数成功就是完全成功,失败的话,程序会回复到“之前的状态”。这种一般采用 copy and swap 的策略:为你打算修改的对象做出一份副本,然后再那副本的身上做一切要改变的修改莫若没有动作抛出异常,那么原来对象和副本进行一个不抛出异常的操作中置换,如果有任何异常,那么原对象任然保持不变。这种手法是 pimpl idiom。

5.  不抛掷保证。

 

条款30:透彻了解Inline的里里外外。

一般来说inline 关键字一加就是内联函数,主要用于短小的函数中,因为inline函数其实是把代码复制到当前的代码中去,而不是真正的函数调用,所以它像函数但是又不是函数的调用,所以一般这样长数量的代码段中不用inline函数,inline函数代替宏来说有很大的优势,例如自增自减的问题,它一般是定义于头文件中,

但是inline函数来说如果通过函数之后怎而进行的调用 可能不会inline,如:

Inline void f(){}  void (*pf)() = f;   f(); //OK   pf();  //error

但是处理inline函数的时候要小心,是否应该把这个函数当做inline函数,例如派生类中的构造函数和析构函数,该不该是inline,就算其中的代码是空,但是那只是你眼睛欺骗了你,如果派生类有3个string ,成员数据,基类中也有,那么派生类的构造函数虽然为空,但是要执行的动作依然是基类的构造,然后try catch{} 看看3个string 的 构造是否成功,如果基类中也有,那么这个代码量其实就是非常大的,所以inline的使用要小心的确定,用在小,频繁调用的身上,可使日后的调试过程和二进制的升级更容易。也可使潜在的代码膨胀问题最小化,使程序的速度提升机会最大化。大部分的inline 是发生在编译的过程中的。

 

条款31:将文件的编译依存关系降至最低。

在实现类中,内的成员数据只含有一个指针,指向其实现类,这样的设计一般叫做

Pimpl idiom (pointer to implementation), 内含的指针名一般叫做 pImpl。

这样真正的“接口和实现分离”,当class中任何的实现细目修改的时候,不需要重新编译,客户也看不到实现的细目。

分离的关键:以“声明的依存性” 替换“定义的依存性”,那正是编译依存性的最小化本质,

1. 如果使用对象的引用或者指向对象的指针就可以,那么没有必要使用对象,声明就可以了。

2. 尽量以类的声明式替换类的定义式。

3. 为声明式和定义式提供不同的头文件。

使用pimpl idiom 的class  叫做 Handle classes .  还有一种interface classes

这两种设计解除了接口和实现之间的耦合关系,降低了文件间的编译依存性。

 

条款32:确定你的public 继承塑模出is -a 的关系

Public 继承意味着 is -a ,:适用于基类身上的每一件事情一定也适用于派生类身上,因为每一个派生类对象也都是一个基类对象。可参考的一些错误的例子如矩形正方形,鸟企鹅等。

好的接口可以防止无效的代码通过编译,因此你应该宁可采取“在编译期间拒绝“

而不是在”运行期间”。

 

条款33:避免遮掩继承而来的名称

当一个派生类继承基类,派生类继承了基类的所有东西,实际运作的方式是:派生类作用域被嵌套在基类的作用域内。当一个派生类中的函数A被调用它里面含有另一个函数B的时候,这个时候查找的顺序是:先从Local作用域中也就是A函数的作用域中找是否有B函数,没有再查找派生类覆盖的作用域中,还是没有,那么就查找外围的基类,如果还是没有查找内含基类的作用域,最后在全局作用域中查找。

当基类中和派生类中有相同名称的函数时候,通过派生类的对象调用的是派生类中的函数,这样就把基类中的函数给掩盖起来了,如果想让基类被掩盖的名称可见,可以使用Using 声明式。(或转交函数)。

 

条款34:区分接口继承和实现继承

1. 成员函数的接口总是会被继承的。

2. 声明一个纯虚函数是为了让派生类只继承函数的接口。但我们可以为纯虚函数提供一份实现代码,唯一调用的方法是通过基类名称调用。

3. 非纯虚函数是为了让派生类继承该函数的接口和缺省的实现代码。

4. 声明非虚拟函数是为了让派生类继承接口和一份强制实现的代码。

 

条款35: 考虑virtual 函数以外的其他选择。

NVI 手法:所谓的Template Method设计模式。是用Public non-virtual函数间接的调用private virtual 函数。优点在于在做一些工作之前和工作之后能做一些事情,如加互斥锁,释放锁等一些操作。

Strategy 设计模式。

1. 将virtual 函数替换为“函数指针成员变量”,这是一部分

2. 以tr1::function成员替换virtual 函数允许使用任何可调用物搭配一个兼容于需求的签名式,
3. 将基础体系内的virtual 函数替换为另一个继承体系内的virtual函数。

 

条款36:绝不重新定义继承而来的non-virtual 函数

条款37:绝不重新定义继承而来的缺省参数值

缺省的参数值都是静态绑定的,而virtual 函数 唯一应该覆写的却是动态绑定的。

你想让基类和派生类都有一个共同的默认值,那么采用NVI手法。

 

条款38:通过复合塑模出has-a或根据某物实现出。

复合的意义和public 继承完全不同。

复合意味has-a(有一个),我想应该是我们常说的组合关系。

 

条款39:明智而审慎的使用private 继承。

条款40:明智而审慎的使用多重继承

 

智慧旅游解决方案利用云计算、物联网和移动互联网技术,通过便携终端设备,实现对旅游资源、经济、活动和旅游者信息的智能感知和发布。这种技术的应用旨在提升游客在旅游各个环节的体验,使他们能够轻松获取信息、规划行程、预订票务和安排食宿。智慧旅游平台为旅游管理部门、企业和游客提供服务,包括政策发布、行政管理、景区安全、游客流量统计分析、投诉反馈等。此外,平台还提供广告促销、库存信息、景点介绍、电子门票、社交互动等功能。 智慧旅游的建设规划得到了国家政策的支持,如《国家中长期科技发展规划纲要》和国务院的《关于加快发展旅游业的意见》,这些政策强调了旅游信息服务平台的建设和信息化服务的重要性。随着技术的成熟和政策环境的优化,智慧旅游的时机已经到来。 智慧旅游平台采用SaaS、PaaS和IaaS等云服务模式,提供简化的软件开发、测试和部署环境,实现资源的按需配置和快速部署。这些服务模式支持旅游企业、消费者和管理部门开发高性能、高可扩展的应用服务。平台还整合了旅游信息资源,提供了丰富的旅游产品创意平台和统一的旅游综合信息库。 智慧旅游融合应用面向游客和景区景点主管机构,提供无线城市门户、智能导游、智能门票及优惠券、景区综合安防、车辆及停车场管理等服务。这些应用通过物联网和云计算技术,实现了旅游服务的智能化、个性化和协同化,提高了旅游服务的自由度和信息共享的动态性。 智慧旅游的发展标志着旅游信息化建设的智能化和应用多样化趋势,多种技术和应用交叉渗透至旅游行业的各个方面,预示着全面的智慧旅游时代已经到来。智慧旅游不仅提升了游客的旅游体验,也为旅游管理和服务提供了高效的技术支持。
智慧旅游解决方案利用云计算、物联网和移动互联网技术,通过便携终端设备,实现对旅游资源、经济、活动和旅游者信息的智能感知和发布。这种技术的应用旨在提升游客在旅游各个环节的体验,使他们能够轻松获取信息、规划行程、预订票务和安排食宿。智慧旅游平台为旅游管理部门、企业和游客提供服务,包括政策发布、行政管理、景区安全、游客流量统计分析、投诉反馈等。此外,平台还提供广告促销、库存信息、景点介绍、电子门票、社交互动等功能。 智慧旅游的建设规划得到了国家政策的支持,如《国家中长期科技发展规划纲要》和国务院的《关于加快发展旅游业的意见》,这些政策强调了旅游信息服务平台的建设和信息化服务的重要性。随着技术的成熟和政策环境的优化,智慧旅游的时机已经到来。 智慧旅游平台采用SaaS、PaaS和IaaS等云服务模式,提供简化的软件开发、测试和部署环境,实现资源的按需配置和快速部署。这些服务模式支持旅游企业、消费者和管理部门开发高性能、高可扩展的应用服务。平台还整合了旅游信息资源,提供了丰富的旅游产品创意平台和统一的旅游综合信息库。 智慧旅游融合应用面向游客和景区景点主管机构,提供无线城市门户、智能导游、智能门票及优惠券、景区综合安防、车辆及停车场管理等服务。这些应用通过物联网和云计算技术,实现了旅游服务的智能化、个性化和协同化,提高了旅游服务的自由度和信息共享的动态性。 智慧旅游的发展标志着旅游信息化建设的智能化和应用多样化趋势,多种技术和应用交叉渗透至旅游行业的各个方面,预示着全面的智慧旅游时代已经到来。智慧旅游不仅提升了游客的旅游体验,也为旅游管理和服务提供了高效的技术支持。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HarkerYX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值