2018年10月22日 星期一

[Effective C++] Prefer const, enums, and inlines to #defines


Prefer const, enums, and inlines to #defines





#define ASPECT_RATIO 1.653
// 1. Never been seen by compilers, removed by the preprocessor
// 2. ASPECT_RATIO not get entered into the symbol table
// 3. Multiple copies of 1.653 in object code by preprocessor

const double AspectRatio = 1.653;
// 1. Seen by compilers
// 2. Get entered into the symbol table
// 3. Smaller code: never result in more than one copy
// 4. No storage for const objects of integral types, unless create a pointer or ref

const char * const strName = "Gary Hsieh";
// const pointer to const char

#include <string>
const std::string stdStrName = "Gary Hsieh";
// std::string object are generally preferable to char*-based progenitor.

/* About class-specific constants */
class GamePlayer {
private:
 static const int NumTurns = 5;
 // 1. A declaration, not a definition
 // 2. Usally need a definition, constant that are static and of integral type(e.g., int, bool, char) are an exception
 // 3. If not take address, can provide no definition

 int scores[NumTurns];
};

const int GamePlayer::NumTurns;
// 1. Need address or compiler incorrectly insist on a definition
// 2. Put in implementation file
// 3. No initial value is permitted, because declaration has one

class DefineInClass {
 int wrong[SOME_NUM];
 // compiler error

private:
#define SOME_NUM 123
// 1. #define don't respect scope: if defined, will be in force for the rest of the compilation
// 2. no private define
 int correct[SOME_NUM];
};

class CostEstimate {
private:
 static const double FudgeFactor;
};
const double CostEstimate::FudgeFactor = 1.35;
// For compilers don't accept the syntax above

/* Enum Hack */
class GamePlayer {
private:
 enum { NumTurns = 5 };
 int scores[NumTurns];
 // If compilers insist knowing NumTurns and declaration with initial value is not accepted
};
// 1. Behave like #define: can not take address
// 2. No unnecessary memory allocation
// 3. Lots of code employs it and a fundamental technique of template metaprogramming

/* Macros -> functions */
#define CALL_WITH_MAX(a,b) isdigit((a) > (b) ? (a) : (b))
// 1. Don't incur the overhead of a function call
// 2. Remember to parenthesize

int a = 5, b = 0;
bool x = CALL_WITH_MAX(++a, b);  // a is incremented twice
bool y = CALL_WITH_MAX(++a, b + 10); // a is incremented once

template<typename T>
inline void callWithMax(const T& a, const T& b) {
 isdigit(a > b ? a : b);
}
// 1. Template for an inline function
// 2. Efficiency of a macro, predictable behavior(no need to parenthesize), type safety
// 3. Obeys scope and access rules, e.g., private in a class

沒有留言:

張貼留言