effective c++:尽量替换define,确保对象使用前初始化
#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,确保对象使用前初始化的更多相关文章
- effective c++(04)之对象使用前初始化
对于内置类型以外的初始化责任落在构造函数身上.如下: class PhoneNumber{}; class ABEntry{ public: ABEntry( const string& na ...
- Effective C++ 之 Item 2:尽量以 const, enum, inline 替换 #define
Effective C++ Chapter 1. 让自己习惯C++(Accustoming Yourself to C++) Item 2. 尽量以 const, enum, inline 替换 #d ...
- Effective C++学习笔记 条款02:尽量以const,enum,inline替换 #define
尽量使用const替换 #define定义常量的原因: #define 不被视为语言的一部分 宏定义的常量,预处理器只是盲目的将宏名称替换为其的常量值,导致目标码中出现多分对应的常量,而const定义 ...
- Effective C++_笔记_条款02_尽量以const、enum、inline替换#define
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 这个条款或许改为“宁可以编译器替换预处理器”比较好,因为或许#d ...
- 《Effective C++》读书笔记 条款02 尽量以const,enum,inline替换#define
Effective C++在此条款中总结出两个结论 1.对于单纯常量,最好以const对象或enum替换#define 2.对于形似函数的宏,最好改用inline函数替换#define 接下来我们进行 ...
- 【Effective C++ 读书笔记】条款02: 尽量以 const, enum, inline 替换 #define
条款02: 尽量以 const, enum, inline 替换 #define 这个条款或许可以改为“宁可以编译器替换预处理器”. 编译过程: .c文件--预处理-->.i文件--编译--&g ...
- Effective C++阅读笔记_条款2:尽量以const,enum,inline替换#define
1.#define缺点1 #define NUM 1.2 记号NUM可能没有进入记号表,在调试或者错误信息中,无法知道1.2的含义. 改善:通过const int NUM = 1.2; 2.#dein ...
- Book. Effective C++ item2-尽量使用const, enum, inline替换#define
##常规变量 c++里面的#define后面的定义部分,是不算代码的一部分的.所以如果你使用#define: #define ASPECT_RATIO 1.653 你希望这个代号ASPECT RATI ...
- 【02】尽量以const,enum,inline替换#define
1.考虑为什么? 首先,#define不是语言的一部分,而是预编译过程.也就是在编译器编译之前,进行文本替换.考虑#define Pi 3.1425:在编译之前,Pi都会被文本替换为3.1415,因此 ...
随机推荐
- [原]武大预选赛F题-(裸并查集+下标离散化+floyd最短路)
Problem 1542 - F - Countries Time Limit: 1000MS Memory Limit: 65536KB Total Submit: 266 Accepted: 36 ...
- Java面试汇总
转自:http://zy19982004.iteye.com/blog/1846537#comments 一.All 最近找工作,遇到的笔试面试题,归纳如下,供大家参考. 二.J2SE 容器 Hash ...
- IO(一)
文件相关 package com.bjsxt.io.file; import java.io.File; /** * 两个常量 * 1.路径分隔符 ; * 2.名称分隔符 /(windows) /(l ...
- [HIHO1299]打折机票(线段树)
题目链接:http://hihocoder.com/problemset/problem/1299 线段树,按照t为下标去更新v,更新的时候要保留最大的那个. #include <algorit ...
- 《OD学Oozie》20160807Oozie
一.引入 MapReduce Job Hive 脚本任务 同一个业务:先后.定时调度 工作流: 定义工作流程 activity jbpm oozie: 大数据工作流定义与调度框架 专门定义与调度Map ...
- CString和string
CString和string(一) 概述 string和CString均是字符串模板类,string为标准模板类(STL)定义的字符串类,已经纳入C++标准之中: CString(typedef CS ...
- 解同余式ax ≡ c(mod m)
将式子变形为 ax-c=my 可以看出原式有解当且仅当线性方程ax-my=c有解 设g = gcd(a, m) 则所有形如ax-my的数都是g的倍数 因此如果g不整除c则原方程无解. 下面假设g整除c ...
- 51nod1556 计算
ans[n]=ans[n-1]*3-m[n-2];YY一下可以懂的.减掉的就是往下走的情况不符合正整数的情况.m是默慈金数. #include<cstdio> #include<cs ...
- 一个小面试题sql
一. 问答题 1简要说明分页是如何实现的. A:sqlserver: Select top(pagesize) * from student where id not in( ...
- 类的加载到反射reflect
类的加载: 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载.连接.初始化这三个步骤来实现对这个类进行初始化. 加载: 就是指将class文件加载进入内存,并为之创建一个Class对 ...