【问题标题】:How to correctly define constants in C++如何在 C++ 中正确定义常量
【发布时间】:2017-07-18 07:44:15
【问题描述】:

我在许多 C++ 代码库中看到了一个共同的模式:

Header.h:

static const int myConstant = 1;

Source1.cpp:

#include "Header.h"

Source2.cpp:

#include "Header.h"

基于:

3.5 程序及联动

...

(2.1) — 当名称具有外部链接时,它所表示的实体可以由范围内的名称引用 其他翻译单元或来自同一翻译单元的其他范围。

(2.2) — 当名称具有内部链接时,它所表示的实体可以由其他范围的名称引用 在同一个翻译单元中。

...

3 具有命名空间范围 (3.3.6) 的名称如果是以下名称,则具有内部链接

(3.1) — 显式声明为静态的变量、函数或函数模板;或者,

myConstant 只能从同一个翻译单元访问,编译器将生成它的多个实例,每个包含Header.h 的翻译单元一个。

我的理解是否正确 - 创建了多个 myConstant 实例?如果是这种情况,请您指出在 C++ 中使用常量的更好选择

编辑:

有人建议在标题中创建myConstant extern 并将其定义在一个cpp 文件中。这是一个好习惯吗?我这会使编译器看不到该值并阻止许多优化,例如当该值出现在算术运算中时。

【问题讨论】:

  • 如何标记它constexpr?编译器可能会优化它。
  • 为什么不为此使用预处理器#define?
  • @Veda 这被认为是一种不好的做法。反之亦然。尽可能使用const 代替#define
  • const 变量在 C++ 中始终被视为常量表达式,除非它们的 odr 用途需要另外使用(例如获取它们的地址)。如果您仅将它们用作真正的常量,则甚至不需要 static 限定符。

标签: c++


【解决方案1】:

你正在做的应该没问题。优化器可能会避免为常量创建任何存储,而是用值替换它的任何使用,只要您从不获取变量的地址(例如&myConstant)。

【讨论】:

    【解决方案2】:

    头文件中出现的static const int myConstant = 1 模式有点奇怪,因为关键字static 将变量定义的范围限制为特定的翻译单元。因此,不能从其他翻译单元访问此变量。所以我不明白为什么有人可能会在头文件中公开一个变量,尽管这个变量永远不能从“外部”寻址。

    请注意,如果不同的翻译单元包含标题,那么每个翻译单元将定义自己的,有点“私有”这个变量的实例。

    我认为常见的模式应该是:

    在头文件中:

    extern const int myConstant;
    

    在整个程序的一个实现文件中:

    const int myConstant = 1;
    

    然而,cmets 说,这将阻止编译器进行优化,因为在编译翻译单元时不知道常量的值(这听起来很合理)。

    因此,“全局/共享”常量似乎是不可能的,人们可能不得不在头文件中使用 - 有点矛盾 - 关键字 static

    另外,我会使用constexr 来表示编译时间常数(尽管编译器可能会派生这个):

     static constexpr int x = 1;
    

    因为static-关键字仍然以某种方式打扰我,所以我对constexpr 进行了一些研究和实验,没有static 关键字但使用extern 关键字。不幸的是,extern constexpr 仍然需要初始化(这使它成为一个定义并导致重复的符号错误)。有趣的是,至少使用我的编译器,我实际上可以在不同的翻译单元中定义constexpr int x = 1,而不会引入编译器/链接器错误。但是我在标准中没有找到对这种行为的支持。但是在头文件中定义constexpr int x = 1static constexpr int x = 1还要好奇。

    这么多词,很少发现。我认为static constexpr int x = 1 是最好的选择。

    【讨论】:

    • 请看我的编辑,我认为在这种情况下编译器看不到该值。
    • 除非myConstant 的地址被占用(或其他一些棘手的 odr 使用),否则可能不会有任何变量。
    • @StoryTeller 我认为如果您使用 extern,编译器必须创建一个变量。该名称必须可以从任何地方访问(可能在库中)。
    • 它的关键字const 可以让编译器做很多优化;它可能根本不会定义变量。
    • @Felics - 道歉。我最初的评论是关于 “请注意,如果不同的翻译单元包含标题,那么每个翻译单元将定义它自己的,有点“私有”的这个变量的实例。” 虽然我假设你说的是一般情况。此答案仅适用于运行时常量。然后你必须小心静态初始化顺序惨败。
    猜你喜欢
    • 1970-01-01
    • 2011-09-18
    • 1970-01-01
    • 1970-01-01
    • 2011-06-03
    • 1970-01-01
    • 2010-12-20
    • 2011-10-17
    • 1970-01-01
    相关资源
    最近更新 更多