gpt4 book ai didi

c++ - 在 C++1z 中定义全局常量?

转载 作者:可可西里 更新时间:2023-11-01 17:37:48 33 4
gpt4 key购买 nike

中声明内存高效全局常量的最佳方法是什么? C++1z 哪个不做internal linkage ,因此尽管所有 translation units 都使用单个拷贝?

虽然在很多地方都提到过,但我们没有任何单一的“最佳方法”问题和答案,所以就在这里。这是我发现相关问题的部分地方列表。

  • constexpr global constants in a header file and odr
  • global declarations/initializations using static, const, constexpr
  • Global Constants in C++11
  • Defining global constant in C++
  • c++ global constants issue
  • Global Constants vs. Enumeration
  • Proper way to make a global “constant” in C++

  • 我正在寻找至少适用于所有基本类型的解决方案,例如 int , double , char , std::string .

    编辑 1:
    最好的方式是,我的意思是“内存高效”。我知道内部链接会为每个翻译单元制作多个拷贝,因此会占用内存。除此之外,如果我们能够实现快速的执行时间和编译时间,那就太好了,代码的美化(容易程度)并不重要。我也知道外部链接会增加获取时间,因为处理器可能会在运行时缓存未命中。但是最新的 C++ 语言是否支持所有这些的最佳方法?或者可能建议支持每个案例?

    注:还有什么是最好的方法 std::string全局常量 ?是否存在可变性会对常量性产生任何影响?

    最佳答案

    概括

    在 C++17 中,定义全局常量或全局变量的最简单方法通常是使用 inline variable .您只需将如下一行放入头文件中即可创建一个:

    inline const std::string greeting = "Hello!";

    如果全局常量是 literal type , 更喜欢使用 inline constexpr (如果 inline 是静态类成员,则它是可选的)而不是 inline const :
    inline constexpr std::string_view greeting = "Hello!"sv;

    这也适用于变量,但许多优点不再适用,因此您可能需要使用另一种方法:
    inline unsigned int score = 0;

    细节

    一、二主 迪斯 这种方法的优点是:
  • 它在 C++17 之前不起作用,因此如果您需要 C++14 或更早版本的兼容性,则需要做其他事情。 template trick VTT suggests与旧标准兼容,并且应该具有与内联变量相似的语义,但如果您只需要 C++17 支持,则不再需要它。
  • 编译速度比 extern variables 慢一些,因为编译器需要合并多个定义,并且因为优化器可以获得更多信息。如果您可能会更改定义,而不是数据类型,“有点”部分会变成“明显”部分;由于该值现在位于头文件中,这意味着重新编译包含头文件的所有内容,而不仅仅是重新链接。如果您可能需要更改数据类型,则无论如何都需要重新编译。

  • 如果这些对你来说都不重要,我认为这种方法胜过用 external linkage 获得全局常数的其他方法。并且在最终的可执行文件中至多¹一个定义²。

    像这样的内联变量只在一个文件中提到,所以很容易改变;这对于只有头文件的库特别有用。这也意味着它在编译时具有可用的值,因此优化器可以看到它并可能消除一些用法。

    使用 constexpr
    在 C++17 中,静态 constexpr类(class)成员自动 inline ,所以如果你的全局常量应该是一个类的范围的一部分,你可以做类似的事情
    constexpr int favorite_number = -3;

    否则,您将需要说 constexpr inline ,这应该仍然有效。这将具有上述语义,但也具有 constexpr 通常的优点。 ,所以编译器会知道它可以在编译时尝试做更多的事情。例如:
    #include <string_view>

    using namespace std::literals;

    inline constexpr std::string_view greeting = "Hello!"sv;

    inline constexpr int scrabble_points[greeting.size()] = {4, 1, 1, 1, 1, 0};

    int main() {
    int total = 0;
    for (int i : scrabble_points) {
    total += i;
    }
    return total;
    }

    可以使用 constexpr ,但不仅仅是 inline ,因为与 constexpr它知道 greeting.size()是一个编译时常量,可以用作数组的大小。³ 通过优化,这个 could compile to a just a single mov instruction and ret , 不包括字符串或数组的任何拷贝,因为它是不必要的。

    使用新的内联语义,之前的所有内容 main可能已经包含在多个位置的头文件中,并且仍然最多只有一个拷贝。

    变量

    同样的方法通过省略 const 轻松支持可变变量:
    inline std::string player_name = "<subject name here>";

    这是一个具有外部链接的全局变量。由于它是一个变量,我在 Pete’s answer 上提到的大多数优点消失了,但有些(比如只在一个地方声明变量而不需要链接任何额外的东西)仍然存在。但是,它们可能不值得稍微增加编译时间和缺乏 C++14 兼容性。

    ¹ 对于 constconstexpr变量,如果不需要,编译器/优化器可能会完全消除该变量。从理论上讲,它可能会决定将其复制为立即值或其他值;实际上,您可能不应该担心这一点,因为它只有在有充分理由的情况下才会这样做,并且这应该会使最终的可执行文件更小和/或更快。你可以用 -Os 来调整这个而不是 -O3 .

    ² 每个使用该常量的目标文件仍然会有一个拷贝,但它们会在链接时合并。避免这种情况的唯一方法是使用 extern变量。

    ³ 即使没有 inline,这个简化的例子也能工作,或者数组只有 const而不是 constexpr ,但这些对于更复杂的现实世界情况很有用。

    关于c++ - 在 C++1z 中定义全局常量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45710667/

    33 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com