Effective C++条款粗略总结

Effective C++

1、类/结构体

1把C++看成一门独立的语言,并不是C语言的扩展。C++高效编程视情况而定,取决于你使用C++的哪一部分
2,对于单纯的常量,最好用以const对象或者enums替换#defines。
const int pi=3.14;**
2.1 对于行驶函数的宏定义,最好改为inline函数替换#defines
宏定义一个函数
#defines MAX(a,b) f((a)>(b)?(a):(b))
Ps:直接把函数变成inline函数,
3.尽可能使用const
将某些东西声明为const可以帮助编译器侦测出错误用法,const可以被施加于任何作用域对象、函数参数、函数返回类型、成员函数体。
编译器强制实施bitwise constness,但你编写程序时应该使用“概念上的常量性”。
当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可以避免代码重复。

Class TextBlock
{
Public:
Const char& operator[](std::size_t position) const
{
Return text[position];
}
char& operator[](std::size_t position)
{
//去除const
Return const_cast<char&>(
//为*this 加上const
static_cast<const TextBlock&>*this)[position] ;
}
}

4.编译器可以暗自为class创建default构造函数,copy构造函数,copy assignment(赋值)操作符,以及析构函数。
5.若不想使用编译器自动生成的函数,就该明确拒绝。
2种方式,1,把这些函数自己写,然后设置成private
2,函数后面写=delete(C++新特性)。

Class Test{
    Test()=delete;
}

6.为多态基类声明virtual函数
如果class带有任何virtual函数,他就应该拥有一个virtual析构函数。
Classes的设计目的如果不是作为base class使用,或不是为了具备多态性,就不该声明virtual析构函数。
7.别让异常逃离析构函数
析构函数绝对不要吐出异常,如果一个被析构函数调用的函数可能抛出异常,析构函数应该可以捕捉任何异常,然后吞下它们或结束程序。
如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数执行该操作。

8.绝不在构造函数和析构过程中调用virtual函数
因为这类调用从不下降至derive class

9.令operator =返回一个reference to *this(返回引用)

10.复制对象时勿忘其每一个成分
Copying函数应该确保复制“对象内的所有成员变量”及“所有base class成分”
不要尝试以某个copying函数实现另一个copying函数。应该将共同机能放进第三个函数中,并由两个copying函数共同调用。

11.让接口容易被正确使用,不易被误用

  • 好的接口很容易被正确使用,不容易被误用,你应该在你的所有接口中努力达成这些性质。
    “促进正确使用”的方法包括接口的一致性,以及内置类型的行为兼容。
    “阻止误用”的方法包括建立新类型,限制类型上的操作,束缚对象值以及消除客户的资源管理责任。
    Shared_ptr支持定制型删除器。这可防范DLL问题,可被用来自动解除互斥锁等等。

12.宁用引用传递替换值传递

  • 引用传递通常比较高效,并可避免切割问题。(内置类型,STL的迭代器,函数对象除外)

13.必须返回对象时,别妄想返回其引用

  • 绝不要返回pointer或引用指向一个局部变量(比如在函数里面创建的临时变量)或返回引用指向一个heap-allocated对象。

14.将成员函数声明为private
15.宁以non-member,non-friend替换member函数

  • 这样做可以增加封装性,包裹弹性和机能扩充性

16.若所有参数都需要类型转换,请为此采用non-member函数
17.考虑写出一个不抛出异常的swap函数,

  • 当std::swap()对你的类型效率不高时,提供一个swap函数,并确定这个函数,不抛出异常。
  • 如果你提供一个member swap,也该提供一个non-member swap用来调用前者。对于class,也请特化std::swap
  • 调用swap时应针对std::swap使用using声明式,然后调用swap并且不带任何命名空间资格修饰
  • 为用户定义类型进行std templates全特化是好的,但千万不要尝试在std内加入某些对std而言全新的东西。

18.避免遮掩继承而来的名称

  • 派生类内的名称会遮挡基类内的名称。在public继承下从来没有人希望如此。
  • 为了让被遮挡的名称再见天日,可使用using声明式或转交函数。

19.区分接口继承和实现继承

  • 接口继承和实现继承不同。在public继承下,派生类总是继承基类的接口
  • Pure virtual函数只具体指定接口继承。
  • 简朴的impure virtual函数具体指定接口继承及缺省实现继承。
  • Non-virtual函数具体指定接口继承以及强制性实现继承。

20.考虑虚函数以外的其他选择
21.绝不重新定义继承而来的non-virtual函数
22.绝不重新定义继承而来的缺省参数值。
23.明智而谨慎的使用private继承。
24.明智而谨慎的使用多继承。

2、资源管理

1.以对象管理资源

  • 为防止资源泄露,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放函数。
  • 智能指针经常被使用

2.在资源管理类中小心copy行为

  • 使用智能指针,可以避免。

3.在资源管理类中提供对原始资源的访问
- APIs往往要求访问原始资源,所以每一个RAII class应该提供一个“取得其所管理之资源”的方法

 - 对原始资源的访问可能经由显式转换或隐式转换。一般而言显式转换比较安全,但隐式转换对客户比较方便。

4.成对使用new和delete时要采取相同形式

  • 因为这2个东西都是成对出现的,采用相同的形式,才可以正确匹配成功,否则会匹配出错,导致出现错误或者出现资源泄露。

5.以独立语句将newed对象置入智能指针

  • 以独立语句将newed对象存储于智能指针中。如果不那么做,一旦异常被抛出,有可能导致难以察觉的资源泄露。
Std::tr1::shared_ptr<T>pw(new T);
Function(pw,....);
//先创建一个对象,防止函数出现异常,导致没有delete掉。

3、实现

1.确定对象被使用之前已被初始化,最好在用对象的时候,再声明与定义。

  • 为内置型对象进行手工初始化,因为C++不保证初始化他们。
  • 构造函数最好使用成员初值列,而不要在构造函数本体内使用赋值操作。初值列列出的成员变量,其排列次序应该和它们在class中的声明次序相同。
Class Test{
  Public:
Test(int a,int b):x(a),y(b){}
Private:
Int x,y;
}
  • 为免除“跨编译单元之初始化次序”问题,请以local static 对象替换non-local static 对象。

2.尽可能延后变量定义式的出现时间。
这样做可增加程序的清晰度并改善程序效果。

3.尽量少做转型动作

  • 如果可以,尽量避免转型,特别是在注重效率的代码中避免dynamic_casts。如果有个设计需要转型动作,试着发展无需转型的替代设计。
  • 如果转型是必要的,试着将它隐藏在某个函数后面。客户税后可以调用这个函数,而不需要将转型放入他们自己的代码。
  • 宁可使用C++转型,也不使用旧时转型。前者容易辨识出来。

4.避免返回handles指向的对象内部成分

  • 避免返回handles(包括引用,指针,迭代器)指向对象内部。遵守这个条款可增加封装性。帮助const成员函数的行为像个const,并将发生“虚吊号码牌”的可能性降至最低。

5.为“异常安全”而努力是值得的

6.透彻了解inline的里里外外

  • 将大多数inline限制在小型,被频繁调用的函数身上。
  • 不要只因为function templates出现在头文件中,就将他们声明为inline。

7.将文件间的编译依存关系降到最低

  • 支持“编译依存性最小化”的一般构想是:想依与声明式而不是定义式。基于此构想的2个手段是handle class和接口类
  • 程序库头文件应该以“完全且仅有声明式”的形式存在,这种做法不论是否涉及templates都使用。

4、模板与泛型编程

1.了解隐式接口和编译期多态

  • Class和template都支持接口和多态。
  • 对于class而言接口是显示的,以函数签名为中心。多态这是通过virtual函数发生于运行期。
  • 对于tempalte参数而言,接口是隐式的,奠基于有效表达式。多态则是通过template具现化和函数重载解析发生于编译期。

2.了解typename的双重意义

  • 请使用关键字typename标识嵌套从属类型名称:但不得在base class lists或member initialization内以他作为base class修饰符。

3.学会处理模板化基类内的名称

4.将与参数无关的代码抽离template

  • Template生成多个classes和多个函数,所以任何template代码都不该与某个构成膨胀的template参数产生相依关系。
  • 因非类型模板参数而造成的代码膨胀,往往可消除。做法是以函数参数或class成员变量替换template参数。

5.运用成员函数模板接受所有兼容类型
6.需要类型转换时请为模板定义非成员函数。
7.请使用traits class表现类型信息。
8.认识template元编程。

5、定制new和delete

1.了解new-handler的行为
2.了解new和delete的合理替换时机。
3.编写new和delete时需要固守常规
4.写了placement new也要写placement delete

6、其他

1.不要忽视编译器的警告
2.让自己熟悉boost
3.让自己熟悉包括TR1在内的标准程序库

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值