返回值优化

以前我们可能会认为C++的复制构造函数会在函数返回时调用,但是现代的编译器对返回值有优化。
wiki上有详细的原文

#include <iostream>

struct C {
  C() {}
  C(const C&) { std::cout << "A copy was made.\n"; }
};

C f() {
  return C();
}

int main() {
  std::cout << "Hello World!\n";
  C obj = f();
  return 0;
}

宏函数可能引发的错误

#define DO_MAX(a,b) f((a) > (b)? (a):(b))
int a = 5, b = 0;
DO_MAX(++a, b);      //a被累加二次
DO_MAX(++a, b+10);   //a被累加一次

可以采用inline模板,照样可以达到宏一样的性能。而且没有这种宏替换带来的缺点,而且有类型检查。

template<typename T>
inline void DO_MAX(const T& x, const T& b) {
    f(a > b ? a : b);
}

对于单纯的常量,最好使用const或者enums,替换#define
对于宏函数,最好改用inline

const 尽可能的使用const

  • const修饰常量
  • const修饰指针本身
  • const修饰成员函数
    表示该成员不会改变类的成员,如果需要改变的某个变量的话,使用mutable修饰成员
    const修饰成员函数时仅仅只是测试该函数执行过程中有没有进行修改或者赋值。如果故意把某个变量的引用返回出去,也可能会被外部修改。
    在const和non-const的成员函数中避免重复,如果需要,通过const_cast进行转换。
  • const修饰函数形参

对象初始化

C++11之前对象初始化不具有线程安全特性
C++的初始化成员次序非常固定,基类早于子类的初始化。析构时,正好相反

C++中对定义于不同编译单元内的全局静态对象的初始化顺序不确定。但是都是在main函数之前。 编译单元其实就是单个cpp文件。 最常见而且容易被忽略的情况是 non local static的模板类成员。模板类在被使用时编译才具体化。
C++中的local static对象一定会在第一次使用时定义。

A * getInstance() {
   static A * m;
   if (m == nullptr) {
      Lock();
      m = new A();
      UnLock();
   }
   return A;
}  //这段代码在c++11之前 线程不安全

void test() {
   cout << "before a";
   static A a();           //假设a构造是输出 I am created.
   cout << "after a";     
} // 这段代码的输出结果是, 先before,再I am created,再after

C++的默默编写的函数

  • 构造函数
  • 析构函数
  • 复制构造函数
  • 赋值重载

若不想使用编译器自动生成的函数,就要明确拒绝

C++11中 使用 delete 可以删除默认的函数
之前的版本,可以显式声明,并且设置为private。不需要实现。

多态基类的析构函数声明为virtual

否则对指向子类的基类指针使用delete时候,会产生内存泄露。