Begin reading 'Effective c++'

I am feeling my English poor,especially in IT areas,it  need to read many foreign resources .

I plan to read some classic books about c++.

I hope I can insist on writing some notes here.

Not only it can enhance my c++ abilities,but also it can strengthen my English skills.

 


 

Item 1:  Prefer const and inline to #define

why ? It 's easy to find errors when you use "const".also exactly.

in c++ period ,we must give up some things that in c period,such #define .

 

This Item might better be called  " prefer the compiler to the preprocessor, "  because  #define  is often treated as if it's not part of the language per se. That's one of its problems. When you do something like this, 

#define  ASPECT_RATIO 1.653

the symbolic name ASPECT_RATIO may never be seen by compilers; it may be removed by the preprocessor before the source code ever gets to a compiler. As a result, the name ASPECT_RATIO may not 
get  entered into the symbol table. This can be confusing  if  you  get  an error during compilation involving the use of the constant, because the error message may refer to  1.653 , not ASPECT_RATIO. If ASPECT_RATIO was defined  in  a header file you didn ' t write, you ' d then have no idea  where  that  1.653  came from, and you ' d probably waste time tracking it down. This problem can also crop up in a symbolic debugger, because, again, the name you ' re programming with may not be  in  the symbol table. 

The solution to 
this  sorry scenario  is  simple and succinct. Instead of  using  a preprocessor macro, define a constant: 

const   double  ASPECT_RATIO  =   1.653 ;

This approach works like a charm. There are two special cases worth mentioning, however. 

First, things can 
get  a bit tricky when defining constant pointers. Because constant definitions are typically put  in  header files ( where  many different source files will include them), it ' s important that the pointer be declared const, usually in addition to what the pointer points to. To define a constant char*-based string in a header file, for example, you have to write const twice: 

const   char   *   const  authorName  =   " Scott Meyers " ;

For a discussion of the meanings and uses of 
const , especially  in  conjunction with pointers, see Item  21

Second, it
' s often convenient to define class-specific constants, and that calls for a slightly different tack. To limit the scope of a constant to a class, you must make it a member, and to ensure there ' s at most one copy of the constant, you must make it a  static  member: 

class  GamePlayer  {
private:
  
static const int NUM_TURNS = 5;    // constant declaration
  int scores[NUM_TURNS];             // use of constant
  ...
}
;

There
' s a minor wrinkle, however, which is that what you see above is a declaration for NUM_TURNS, not a definition. You must still define static class members in an implementation file: 

const   int  GamePlayer::NUM_TURNS;       //  mandatory definition;
                                      
//  goes in class impl. file

There
' s no need to lose sleep worrying about this detail. If you forget the definition, your linker should remind you. 

Older compilers may not accept 
this  syntax, because it used to be illegal to provide an initial value  for  a  static   class  member at its point of declaration. Furthermore,  in - class  initialization  is  allowed only  for  integral types (e.g., ints, bools, chars, etc.), and only  for  constants. In cases  where  the above syntax can ' t be used, you put the initial value at the point of definition: 

class  EngineeringConstants  {      // this goes in the class
private:                          // header file
  static const double FUDGE_FACTOR;
  ...
}
;
//  this goes in the class implementation file
const   double  EngineeringConstants::FUDGE_FACTOR  =   1.35 ;

This 
is  all you need almost all the time. The only exception  is  when you need the value of a  class  constant during compilation of the  class , such  as   in  the declaration of the array GamePlayer::scores above ( where  compilers insist on knowing the size of the array during compilation). Then the accepted way to compensate  for  compilers that (incorrectly) forbid the  in - class  specification of initial values  for  integral  class  constants  is  to use what  is  affectionately known  as   " the enum hack. "  This technique takes advantage of the fact that the values of an enumerated type can be used  where  ints are expected, so GamePlayer could just  as  well have been defined like  this

class  GamePlayer  {
private:
  
enum { NUM_TURNS = 5 };    // "the enum hack" — makes
                             
// NUM_TURNS a symbolic name
                             
// for 5
  int scores[NUM_TURNS];     // fine
...
}
;

Unless you
' re dealing with compilers of primarily historical interest (i.e., those written before 1995), you shouldn ' t have to use the  enum  hack. Still, it ' s worth knowing what it looks like, because it ' s not uncommon to encounter it  in  code dating back to those early, simpler times. 

Getting back to the preprocessor, another common (mis)use of the 
#define  directive is using it to implement macros that look like functions but that don't incur the overhead of a function call. The canonical example is computing the maximum of two values: 

#define  max(a,b) ((a) > (b) ? (a) : (b))

This little number has so many drawbacks, just thinking about them 
is  painful. You ' re better off playing in the freeway during rush hour. 

Whenever you write a macro like 
this , you have to remember to parenthesize all the arguments when you write the macro body; otherwise you can run into trouble when somebody calls the macro with an expression. But even  if  you  get  that right, look at the weird things that can happen: 

int  a  =   5 , b  =   0 ;
max(
++ a, b);          //  a is incremented twice
max( ++ a, b + 10 );       //  a is incremented once

Here, what happens to a inside max depends on what it 
is  being compared with !  

Fortunately, you don
' t need to put up with this nonsense. You can get all the efficiency of a macro plus all the predictable behavior and type-safety of a regular function by using an inline function (see Item 33): 

inline 
int  max( int  a,  int  b)  return a > b ? a : b; }

Now 
this  isn ' t quite the same as the macro above, because this version of max can only be called with ints, but a template fixes that problem quite nicely: 

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

This template generates a whole family of functions, each of which takes two objects convertible to the same type and returns a reference to (a constant version of) the greater of the two objects. Because you don
' t know what the type T will be, you pass and return by reference for efficiency (see Item 22). 

By the way, before you consider writing templates 
for  commonly useful functions like max, check the standard library (see Item  49 ) to see  if  they already exist. In the  case  of max, you ' ll be pleasantly surprised to find that you can rest on others '  laurels: max  is  part of the standard C ++  library. 

Given the availability of consts and inlines, your need 
for  the preprocessor  is  reduced, but it ' s not completely eliminated. The day is far from near when you can abandon #include, and #ifdef/#ifndef continue to play important roles in controlling compilation. It ' s not yet time to retire the preprocessor, but you should definitely plan to start giving it longer and more frequent vacations. 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值