Effective C++(1-2) 编译器替换预处理器
1 C++最主要的四部分:
- C
- Object-Oriented C++: 面向对象
- Template C++:泛型编程
- STL
C++高效编程守则视状况而变化,取决于你使用C++的哪一部分。
2 尽量以const, enum , inline替换 #define
2.1
#define ASPECT_RATIO 1.653记号名称ASPECT_RATIO在被编译器识别之前,已经被预编译器替换为1.653了,所以名称ASPECT_RATIO有可能没进入记号表内。解决方法:
const double AspectRatio = 1.653;
2.2 关于const的一个知识点性能影响:对浮点常量而言,使用常量可能币使用#define导致较小量的码,因为预处理“盲目地将宏名称ASPECT_RATIO”替换为1.653。
若要定义一个char*字符串,必须写const两次
const char* const authorName = "Scott Meyers";
若替换为String对象则更好:
const std::string authorName("Scott Meyers");
2.3 class专属常量
static, 将常量的作用域限制于class内,且确保此常量至多只有一份实体。class GamePlayer { private: static const int NumTurns = 5; //常量声明式 int scores[NumTurns]; //使用该常量 };
这里的NumTurns是个声明式,而不是定义式。一般情况下,这样做就足够了,声明并使用它,但是有两种情况需要你给出一个关于它的定义式:1 取这个class专属常量的地址2 编译器坚持要看到一个定义式这时候就需要一个额外的定义式:const int GamePlayer::NumTurns; // 由于class常量已在声明时或得初值,因此定义时不可以再设初值。如果旧式的编译器不支持“in-class 初值设定”,那么可以把初值的设定放在定义式中:class CostEstimate { private: static const double FudgeFactor; ... }; ConstEstimate::FudgeFactor = 1.35; // 位于实现文件内
2.4 enum hack
如果你的编译器不够优秀,不允许"static整数型class常量"完成“in class初值设定”,那么,就有必要认识一下enum hack。先看一下补偿的做法:
class GamePlayer { private: enum { EnumTurns = 5 }; int scores[NumTurns]; };
现在来正式认识一下enum hack:
1 enum hack的行为某些方面比较像#define而不是const,如:
- 取一个enum的地址是不合法的,同样的,取一个#define的地址通常也不合法;
- 不允许一个指针或者引用指向某个enum常量;
- Enums和#defines绝不会导致非必要的内存分配。
2 实用主义: 事实上,“enum hack”是template metaprogramming(模版元编程)的基础技术。
2.5 形似函数的宏——>template inline函数
// 以a和b的较大值调用f
#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被累加一次
神奇的事情就是,a的递增次数取决于“它被拿来和谁比较”。
解决办法: template inline函数
template<typename T> inline void callWithMax(const T& a, const T& b) { f ( a > b ? a : b); }
小结:
- 对于单纯常量,最好以const对象或者enum替换#define
- 对于形似函数的宏, 最好改用inline函数替换#define
参考:
《Effective C++ 3rd》