1.让自己习惯C++

 

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

C:区块、语句、预处理器、内置数据类型、数组、指针

面向对象:类、封装、继承、多态、虚函数

模板:泛型编程

STL:容器、迭代器、算法、函数对象

条款02:尽量以const,enum,inline替换#define

#define ASPECT_RATIO 1.653

#define由预处理器处理,不被视为语言的一部分。当运用此常量但获得一个编译错误信息时,也许提到1.653而不是ASPECT_RATIO。这会浪费调试时间

const double AspectRadio = 1.653;

解决之道是以一个常量替换上述的宏

class GamePlayer {
  enum { NumTurns = 5 };
  int scores[NumTurns];
};

当类编译期间需要一个常量,可以使用enum。一个枚举类型的数值可权充int被使用

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

使用#define实现宏,可能导致逻辑错误

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

通过模板inline函数可以获得宏带来的效率

条款03:尽可能使用const

  vector<int> vec;
  const vector<int>::iterator it = vec.begin();
  *it = 10;
  it++; // it是const
  vector<int>::const_iterator it2 = vec.begin();
  *it2 = 10; // *it2是const
  it2++;

使用const指定语义,编译器会强制实施这项约束

class CTextBlock {
public:
  // bitwise const声明,但其实不恰当
  char &operator[](size_t pos) const { return pText[pos]; }
​
private:
  char *pText;
};
  const CTextBlock cctb("Hello");
  char *pc = &cctb[0];
  *pc = 'J'; // bitwise constness

编译器强制实施bitwise constness,但是编写程序应该使用conceptual constness

class CTextBlock {
public:
  const char &operator[](size_t pos) const { return pText[pos]; }
  char &operator[](size_t pos) {
    return const_cast<char &>(static_cast<const CTextBlock &>(*this)[pos]);
  }
​
private:
  char *pText;
};

当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复

条款04:确认对象被使用前已先被初始化

  int x;

在某些语境下x保证被初始化为0,但在其他语境中却不保证

class PhoneNumber {};
class ABEntry {
public:
  ABEntry(const string &name, const string &address, const list<PhoneNumber> &phones);
​
private:
  string theName;
  string theAddress;
  list<PhoneNumber> thePhones;
  int numTimesConsulted;
};
​
ABEntry::ABEntry(const string &name, const string &address,
                 const list<PhoneNumber> &phones) {
  theName = name; // 这些都是赋值而非初始化
  theAddress = address;
  thePhones = phones;
  numTimesConsulted = 0;
}

别混淆了赋值和初始化

ABEntry::ABEntry(const string &name, const string &address,
                 const list<PhoneNumber> &phones)
    : theName(name), theAddress(address), thePhones(phones),
      numTimesConsulted(0) {}

使用成员初始化列表

C++有着十分固定的成员初始化次序。基类早于派生类被初始化,类的成员变量总是以其声明次序被初始化

static对象,其寿命从被构造出来直到程序结束为止。这种对象包括global对象、定义于namespace作用域内的对象、在类内、在函数内、以及在文件作用域类被声明为static的对象。函数内的static对象被称为local static对象,其他static对象被称为non-local static对象。

编译单元是指产出单一目标文件的源码。基本上是单一源码文件加上其所含的头文件。

class FileSystem {
public:
  size_t numDisks() const;
};
extern FileSystem fs;
​
class Directory {
public:
  Directory(params);
};
Directory::Directory(params) { size_t disk = fs.numDisks(); }
Directory tmpDir(params);

C++对定义于不同编译单元的non-local static对象的初始化相对次序并无明确定义。除非fs在tmpDir之前先被初始化,否则tmpDir的构造函数会用到尚未初始化的fs

class FileSytem {};
FileSytem &fs() {
  static FileSytem fs;
  return fs;
}
class Directory {};
Directory::Directory(params) { size_t disks = fs().numDisks(); }
Directory &tmpDir() {
  static Directory dir;
  return dir;
}

单例模式,函数内的local static对象会在该函数被首次调用时初始化。如果从未调用non-local static对象的仿真函数,就不会引发构造和析构成本

任何一种non-const static对象,无论它是local或non-local,在多线程环境下“等待某事发生”都会有麻烦。处理这种麻烦的一种做法是:在程序单线程启动阶段手工调用所有reference-return函数,这可消除与初始化有关的竞速形式

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值