zoukankan      html  css  js  c++  java
  • Effective C++ 笔记 —— Item 2: Prefer consts, enums, and inlines to #defines

    When you do something like this:

    #define ASPECT_RATIO 1.653

    Because #define may be treated as if it's not part of the language per se. The name you defined 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.

    The solution is to replace the macro with a constant:

    const double AspectRatio = 1.653;

    The preprocessor's blind substitution of the macro name ASPECT_RATIO with 1.653 could result in multiple copies of 1.653 in your object code, while the use of the constant AspectRatio should never result in more than one copy.

    When replacing #defines with constants, two special cases are worth mentioning:

    The first is defining constant pointers:

    const char * const authorName = "Scott Meyers";
    const std::string authorName("Scott Meyers");    // better

    The second special case concerns class-specific constants:

    class CostEstimate {
    private:
    static const double FudgeFactor; // declaration of static class
    ... // constant; goes in header file
    };
    const double // definition of static class
    CostEstimate::FudgeFactor = 1.35; // constant; goes in impl. file

    There's no way to create a class-specific constant using a #define, because #defines don't respect scope. Once a macro is defined, it's in force for the rest of the compilation (unless it's #undefed somewhere along the line).

    The accepted way to compensate for compilers that (incorrectly) forbid the in-class specification of initial values for static integral class constants is to use what is affectionately (and non-pejoratively) known as "the enum hack". 

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

    The enum hack behaves in some ways more like a #define than a const does.

    For example, it's legal to take the address of a const, but it's not legal to take the address of an enum, and it's typically not legal to take the address of a #define, either. 

    Also, though good compilers won't set aside storage for const objects of integral types (unless you create a pointer or reference to the object), sloppy compilers may, and you may not be willing to set aside memory for such objects. Like #defines, enums never result in that kind of unnecessary memory allocation.

    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. Here's a macro that calls some function f with the greater of the macro's arguments:

    // call f with the maximum of a and b
    #define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))
    
    int a = 5, b = 0;
    CALL_WITH_MAX(++a, b); // a is incremented twice
    CALL_WITH_MAX(++a, b+10); // a is incremented once

    You can get all the efficiency of a macro plus all the predictable behavior and type safety of a regular function by using a template for an inline function.

    template<typename T>
    inline void callWithMax(const T& a, const T& b) 
    {
        //  because we don't know what T is, we pass by reference-to const
        f(a > b ? a : b);
    }
  • 相关阅读:
    GOF23设计模式之适配器模式(Adapter)
    浅谈浅克隆(shallow clone)和 深克隆(deep clone)
    GOF23设计模式之原型模式(prototype)
    GOF23设计模式之建造者模式(builder)
    GOF23设计模式之工厂模式(factory)
    GOF23设计模式之单例模式(singleton)
    面向对象设计的六大基本原则
    day38 各种队列、Event事件、协程、猴子补丁
    day37 GIL、同步、异步、进程池、线程池、回调函数
    day36 joinablequeue、多线程理论、多线程的两种使用方式、守护线程、互斥锁、死锁、递归锁、信号量
  • 原文地址:https://www.cnblogs.com/zoneofmine/p/14911883.html
Copyright © 2011-2022 走看看