代码之家  ›  专栏  ›  技术社区  ›  gen

我应该避免在C++中使用#define吗?为什么,我可以使用什么替代方案?

  •  3
  • gen  · 技术社区  · 11 年前

    对于某些类型的程序,我需要使用一个恒定的高值来指示一些变量的一些属性。我是说让 color[i] = 1000000; 如果 i 树中的节点未被探索。但我经常在末尾写错0的数字,所以我只是想知道这样做是否更好:

    #define UNEXPLORED 1000000;
    color[i] = UNEXPLORED;
    

    我记得在我读过的某个地方,避免使用#define要好得多。对吗?你将如何解决这个问题?

    3 回复  |  直到 9 年前
        1
  •  5
  •   Some programmer dude    11 年前

    对于简单的常量,您可以使用 const 或者新的 constexpr :

    constexpr unsigned int UNEXPLORED = 1000000;
    

    在这种情况下,使用 常量 常量表达式 。但是,标记了“变量” 常量表达式 在编译时而不是在运行时进行评估,并且可以在只接受文字的地方使用。

        2
  •  4
  •   ForEveR    11 年前

    例如,使用常量。

    const unsigned int UNEXPLORED = 1000000;
    

    或枚举

    enum { UNEXPLORED = 1000000 };
    
        3
  •  0
  •   Dennis    11 年前

    然而,在使用常数时,上面两个答案是正确的 #define 并不局限于该用途。使用的另一个示例 #定义 是宏。

    宏是预处理器使用的代码片段,它们的工作方式与其他代码完全相同 #定义 这方面的声明。预处理器将用宏的代码替换掉您定义的符号的出现。例如:

    #define HELLO_MAC do{ std::cout << "Hello World" << std::endl; }while(false)
    
    int main(int argc, char** argv)
    {
         HELLO_MAC;
    }
    

    这将真正取代 HELLO_MAC 带有我声明的代码的符号。如果它是一个常数,它也会做完全相同的事情。所以你可以考虑 #定义 s表示常量作为一种特定类型的宏。

    使用宏,您还可以传递参数,我发现它对于在代码上强制执行日志记录/异常策略特别有用。 例如

    #define THROW_EXCEPT( ex_type, ex_msg ) /
        do{ throw ex_type( buildExString( (ex_msg), __LINE__, __FILE__ ) ); }while(false)
    
    ... 
    // somewhere else
    THROW_EXCEPT( std::runtime_error, "Unsupported operation in current state" );
    

    该代码使我能够确保每个人都使用引发异常的文件行进行日志记录。

    模板通常是比宏更好的选择,但我不能在本例中使用模板函数,因为我需要使用 __LINE__ __FILE__ 函数的位置,而不是模板函数的位置。

    哪里不应该使用宏?任何你可以使用其他东西的地方。宏,和任何宏一样 #定义 是经过预处理的,所以编译器根本看不到它们。这意味着永远不会为 你好_麦克 THROW_EXCEPT ,因此无法在调试器中看到它们。如果您遇到编译错误,特别是如果它们是长宏,它们也可能会令人困惑。