C++ 进阶笔记之一

优化相关

  • 使用灵活的、动态分配的数据,不要使用固定大小多数组;
  • 优先使用线性算法或者尽量快的算法:算法

    1. push_back 散列表查询:O(1)
    2. set/map lower_bound/upper_bound: O(logN)
    3. vector::insert for_each O(N)
  • 尽量避免劣于线性复杂性的算法,永远不要使用指数复杂性的算法;编程

  • 不要进行不成熟的优化:
    1. 能够用经过引用传递的时候,却定义了经过值传递的方式传递参数;
    2. 可使用前缀++、--运算的时候,却使用了后缀的方式;
    3. 构造函数中使用赋值操做而非初始化列表

并发编程

  • 尽可能减小全局和共享数据
    避免使用名字空间做用域中具备外部链接的数据或者做为静态类成员的数据。若是不得不用,必定要对其仔细进行初始化。在不一样编译单位中这种对象的初始化顺序是未定义的,为此须要高度注意;另外,名字空间做用域中的对象、静态数据成员对象或者跨线程(进程)共享的对象会减小并行性,每每是产生性能和可伸缩性瓶劲的缘由。

例外状况: cin/cout/cerr 比较特殊: cout << "hello world" 等价于
(cout, "hello world");数组

  • 使用C++编写可靠的多线程的代码,认真考虑下面的建议:安全

    1. 参考目标平台的文档,了解改平台的同步原语,好比原子操做、内存屏障
    2. 最好将平台的原语用本身设计的抽象包装起来:好比使用pthread;
    3. 确保正在使用的类型在多线程程序中使用是安全的:
      保证非共享的对象独立;
      肯定在不一样线程中使用该类型的同一个对象究竟是不是须要加锁、考虑最合适的加锁粒度;
  • 若是编写可能用于多线程的类型,必须完成两项任务:多线程

    1. 确保不一样线程能够不加锁地使用该类型的不一样对象;
    2. 必须明确且提供不一样线程使用该类型的同一个对象须要作的操做:
      是否须要考虑外部加锁: 调用者本身负责加锁
      是否须要内部加锁:为每一个公有成员函数的操做加锁。好比生产者-消费者模型一般使用内部加锁。须要考虑:
      第1、 确认该类型的对象老是要被跨线程共享;
      第2、类型接口的设计应该有利于粗粒度、自给自足的操做。若是内部的锁加得很合适,那么对调用者而言是透明无感的。
      第3、不变对象(只读的、常量字符串)不需加锁。
  • 确保资源为对象所拥有,使用显式的RAII和智能指针
    1. 使用RAII时,当心复制构造函数和赋值构造函数;
    2. 使用智能指针而非原始指针来保存动态分配的资源:shared_ptr<T *>
    3. 应该显式地执行资源分配(好比new);
    4. 立刻将申请分配的资源赋予给管理对象:

好比:
void Fun(shared_ptr<Widget> sp1, shared_ptr<Widget> sp2);
Fun(shared_ptr<Widget>(new Widget), shared_ptr<Widget>(new Widget));并发

因为参数初始化的顺序可能由于编译器的不一样而改变,一种极端的状况是:
同时执行了对两个对象的new 操做的内存分配操做,而后再试图调用两个Widget 构造函数。若是这个时候某个构造函数调用抛出异常,另一个对象的内存就永远没有机会释放了。函数

解决方法:绝对不要在一条语句中分配一个以上的资源,应该显式地执行资源分配(好比new),而后立刻将申请分配的资源赋予给管理对象。例如:性能

shared_ptr<Widget> sp1(new Widget);
shared_ptr<Widget> sp2(new Widget);优化

Fun(sp1, sp2);线程

相关文章
相关标签/搜索