#define ASPECT_RATIO 1.653

名为ASPECT_RATIO的值在预编译阶段被替换成1.653,如果在这个常量上出现编译错误,我们可能会困惑1.653的值是什么意思,于是将因为跟踪它而浪费时间。

我们需要使用一个常量来替换上述的宏

const double AspectRatio = 1.653;

当我们以常量替换#define 时,有两种特殊情况需要考虑

第一:常量指针的定义放在头文件内,需要被不同的源代码访问,因此有必要将指针声明为const,如:

const char* const authorName = "Scott Meyers"

或者写成c++形式:

const std::string authorName("Scott Meyers")

第二:为了将常量的作用域限制于class 中,必须让他成为class的一个成员,而为了确保此常量至多只用一份实体,需要声明为static:

class GamePlayer{
private:
static const int NumTurns = ;
int scores[NumTurns];
};

另一个常见#define误用的情况是以它实现宏max(a,b) f((a)>(b)? (a):(b)),该宏看起来像个函数,而且不会招致函数带来的额外开销。

但这往往会带来意想不到的结果:

int a =  ,b = ;
max(++a,b);
max(++a,b+);

第一次调用max时a累加两次,而第二次调用max 时a累加一次,我想这应该不是编写这段程序的人的本意。

遇到上述问题,我们需要使用inline 来替换:

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

这样一来就不用操心参数被求值几次的问题了。

对象使用前初始化

对于无成员内置类型,必须手工完成初始化:

int x = ;
const char* text = "a c-style string";
double d;
std::cin >> d;

至于内置类型外的初始化需要在构造函数中完成,确保每个构造函数都将对象的每个成员初始化。

class PhoneNumber { ... };
class ABEntry { // ABEntry = “Address Book Entry”
public:
  ABEntry(const std::string& name, const std::string& address,
  const std::list<PhoneNumber>& phones);
private:
  std::string theName;
  std::string theAddress;
  std::list<PhoneNumber> thePhones;
  int numTimesConsulted;
};
ABEntry::ABEntry(const std::string& name, const std::string& address,
const std::list<PhoneNumber>& phones)
{
  theName = name; // these are all assignments,
  theAddress = address; // not initializations
  thePhones = phones;
  numTimesConsulted = ;
}

上面这段代码在构造函数体内对成员变量进行赋值,注意:这不叫初始化,真正的初始化是这样的:

ABEntry::ABEntry(const std::string& name, const std::string& address,
const std::list<PhoneNumber>& phones)
: theName(name),
theAddress(address), // these are now all initializations
thePhones(phones),
numTimesConsulted()
{}

这两个版本的构造函数在运行时效果一样,但后者往往效率更高,基于赋值的构造函数在调用构造函数体前已经为成员变量设了初始值,函数体内又进行了一次赋值,从而造成程序运行成本增加。另一方面如果成员变量是const或references就不能赋值,必须在初始化时确定。

初始化的顺序最好按声明顺序来,避免出现不必要的错误,例如:初始化一个数组前,首先初始化数组长度。

对于初始化次序不确定的情况(对不同编译单元的non-local static),则需要以local static替换之。所谓的local static对象指的是函数内的static 对象,其他则成为non-local static 对象。

假设有一个文件系统:

class FileSystem { // from your library’s header file
public:
...
std::size_t numDisks() const; // one of many member functions
...
};
extern FileSystem tfs; // declare object for clients to use
// (“tfs” = “the file system” ); definition
// is in some .cpp file in your library

其中tfs预留给客户使用,如果在客户使用tfs 之前,tfs还没有初始化,就会造成严重后果。

class Directory { // created by library client
public:
Directory( params );
...
};
Directory::Directory( params )
{
...
std::size_t disks = tfs.numDisks(); // use the tfs object
...
} Directory tempDir( params ); // 创建一个Directory对象

其中的tfs与tmpDir是不同人不同时间建立起来的,定义于不同编译单元内,这种情况下就无法保证tfs在tempDir之前被初始化。

我们需要做的就是把non-local static对象放到函数内变为local static,然后让用户调用该函数,这样就可以确保初始化的正确顺序。

class FileSystem { ... }; // as before
FileSystem& tfs() // this replaces the tfs object; it could be
{ // static in the FileSystem class
  static FileSystem fs; // define and initialize a local static object
  return fs; // return a reference to it
}
class Directory { ... }; // as before
Directory::Directory( params ) // as before, except references to tfs are
{ // now to tfs()
  ...
  std::size_t disks = tfs().numDisks();
  ...
}
Directory& tempDir() // this replaces the tempDir object; it
{ // could be static in the Directory class
  static Directory td( params ); // define/initialize local static object
  return td; // return reference to it
}

effective c++:尽量替换define,确保对象使用前初始化的更多相关文章

  1. effective c++(04)之对象使用前初始化

    对于内置类型以外的初始化责任落在构造函数身上.如下: class PhoneNumber{}; class ABEntry{ public: ABEntry( const string& na ...

  2. Effective C++ 之 Item 2:尽量以 const, enum, inline 替换 #define

    Effective C++ Chapter 1. 让自己习惯C++(Accustoming Yourself to C++) Item 2. 尽量以 const, enum, inline 替换 #d ...

  3. Effective C++学习笔记 条款02:尽量以const,enum,inline替换 #define

    尽量使用const替换 #define定义常量的原因: #define 不被视为语言的一部分 宏定义的常量,预处理器只是盲目的将宏名称替换为其的常量值,导致目标码中出现多分对应的常量,而const定义 ...

  4. Effective C++_笔记_条款02_尽量以const、enum、inline替换#define

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 这个条款或许改为“宁可以编译器替换预处理器”比较好,因为或许#d ...

  5. 《Effective C++》读书笔记 条款02 尽量以const,enum,inline替换#define

    Effective C++在此条款中总结出两个结论 1.对于单纯常量,最好以const对象或enum替换#define 2.对于形似函数的宏,最好改用inline函数替换#define 接下来我们进行 ...

  6. 【Effective C++ 读书笔记】条款02: 尽量以 const, enum, inline 替换 #define

    条款02: 尽量以 const, enum, inline 替换 #define 这个条款或许可以改为“宁可以编译器替换预处理器”. 编译过程: .c文件--预处理-->.i文件--编译--&g ...

  7. Effective C++阅读笔记_条款2:尽量以const,enum,inline替换#define

    1.#define缺点1 #define NUM 1.2 记号NUM可能没有进入记号表,在调试或者错误信息中,无法知道1.2的含义. 改善:通过const int NUM = 1.2; 2.#dein ...

  8. Book. Effective C++ item2-尽量使用const, enum, inline替换#define

    ##常规变量 c++里面的#define后面的定义部分,是不算代码的一部分的.所以如果你使用#define: #define ASPECT_RATIO 1.653 你希望这个代号ASPECT RATI ...

  9. 【02】尽量以const,enum,inline替换#define

    1.考虑为什么? 首先,#define不是语言的一部分,而是预编译过程.也就是在编译器编译之前,进行文本替换.考虑#define Pi 3.1425:在编译之前,Pi都会被文本替换为3.1415,因此 ...

随机推荐

  1. postgreSQLG关闭活动的connection、删除活动的数据库

    First, find the activities that are taken place against the target database, you can query thepg_sta ...

  2. 自动化测试LoadRunner

    这个地址应该比较的好下载,以前找的地址都是需要输入一些相关的信息.这个只需要有一个HP的注册账号就可下载,记下来.以备后用: 下载地址: http://www8.hp.com/us/en/softwa ...

  3. Linux屏幕录制gif的工具及教程

    准备 要两个工具配合使用.它们可以用命令行安装,也可以用软件管理器安装. 1,byzanz     安装后有两个命令 byzanz-record   录制,既能录制 Gif 动画,又可录制 Ogv 视 ...

  4. windows 创建SSH Key

    1. 安装git,从程序目录打开 "Git Bash" (百度或用这个连接http://pan.baidu.com/s/1dDJCx9n 下载) 2. 键入命令:ssh-keyge ...

  5. hadoop hadoop-0.20.2-cdh3u4升级

    [hadoop@lab02 ~]$ uname -aLinux lab02 2.6.18-194.el5 #1 SMP Tue Mar 16 21:52:39 EDT 2010 x86_64 x86_ ...

  6. Android View绘制流程

    框架分析 在之前的下拉刷新中,小结过触屏消息先到WindowManagerService(Wms)然后顺次传递给ViewRoot(派生自Handler),经decor view到Activity再传递 ...

  7. JAVA的序列化与反序列化

    一.为什么要进行序列化 再介绍之前,我们有必要先了解下对象的生命周期,我们知道Java对象的生命周期,也即Java中的远程方法调用RMI也会被用到,在网络中要传输对象的话,则必须要对对象进行序列化,关 ...

  8. xxx cannot be resolved to a type 错误解决方法

    (1)jdk不匹配(或不存在)     项目指定的jdk为“jdk1.6.0_18”,而当前eclipse使用的是“jdk1.6.0_22”.需要在BuildPath | Libraries,中做简单 ...

  9. HDU 1525 (博弈) Euclid's Game

    感觉这道题用PN大法好像不顶用了,可耻地看了题解. 考虑一下简单的必胜状态,某一个数是另一个数的倍数的时候是必胜状态. 从这个角度考虑一下:游戏进行了奇数步还是偶数步决定了哪一方赢. 如果b > ...

  10. 移植linux(1)

    硬件环境:TQ2440   软件环境:linux-2.6.30.4 下载源码:ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.30.4.tar ...