1

假设我有一个头文件Resources.h,其中定义了这 5 个结构:

const IColor COLOR_BLACK(255, 0, 0, 0);
const IColor COLOR_GRAY(255, 127, 127, 127);
const IColor COLOR_WHITE(255, 255, 255, 255);
const IColor COLOR_RED(255, 255, 0, 0);
const IColor COLOR_GREEN(255, 0, 255, 0);

使用const(static默认情况下 in C++, 所以internal linkage) 它们“驻留在”翻译单元的范围内。

现在,假设我将这些文件 10 次包含到我的应用程序中(来自 10 个不同的.cpp)。当我编译时,会创建一个目标文件,并且(稍后)链接器会将所有这些目标文件收集在一起,形成一个唯一的机器可运行代码。

这是否意味着当我run编写程序时,它会在内存中分配 10 次以上的每个结构?即 10x5 结构?

因此,即使稍后将它们链接在一起,它们对于翻译单元也是分开的?或者链接器足够聪明,可以将它们收敛到内存中的唯一分配?

不确定我是否正确完成了这些步骤。我对 C++ 很感兴趣。

4

3 回答 3

2

是的。但是(1)即使是最小的可执行文件的通常大小,少数字节也算不上什么,并且(2)它可能无论如何都会被优化掉。如果您想避免这种情况,请使用constexpr,这会使它们仅编译时间值。


在其他新闻中,C++ 中的一个常见约定是仅对宏使用所有大写的标识符。那是因为所有的大写字母都很碍眼,所以这个约定应该保留给通常也不好的东西。当您将所有大写字母用于其他任何内容时,您 (1) 对许多程序员来说似乎是在大喊大叫,并且 (2) 冒着无意的文本替换的风险,以及 (3) 冒着误解这些名称所代表的含义的风险。

C++ 不是 Java 或 Python。

这些语言从早期的 C 中获得了常量全部大写的约定,而早期的 C 没有,const因此它们必须将常量表示为预处理器宏。即,Java 和 Python 约定实际上是 C 中的大写宏约定。在 C++ 中使用宏作为常量已过时,而且与那些语言不同,C++ 确实有预处理器。


另外,请注意:类型的前缀I是指示(抽象)接口的常用约定,但根据您的声明,IColor必须是具体的、可实例化的类型。

于 2018-02-06T08:07:17.307 回答
0

在编译阶段你可能有 10 个,但它们最终可能会在链接阶段得到优化。

不过,您可以为此类 const 变量定义尝试不同的方法,以防由于某些内存限制而需要确定。

拥有你的头文件,只把变量声明作为extern.

// my_consts.h
extern const IColor COLOR_BLACK;

然后在实际定义出现的地方制作一个源文件。

// my_consts.cpp
const IColor COLOR_BLACK(255, 0, 0, 0);

这样,实际定义编译一次,您仍然可以引用它们,因为您已在头文件中声明了它们。

此外,拥有这样的常量,最好将它们粘贴到某个命名空间中以避免全局命名空间污染 - 特别是如果您可以将它们划分为一些逻辑类别。

于 2018-02-06T09:16:40.383 回答
0

请记住:该标准仅指定抽象机器的行为。模拟抽象机器不需要实际的实现,而只需要模拟它的可观察行为。

因此,对于抽象机器,每个内部链接变量的实例都将分配给每个翻译单元。但是由于它们是 const,因此您很可能只使用它们的值而不是它们的地址——用标准术语来说,它们可能不会被 odr 使用(一个定义规则)。在这种情况下,它们将由编译器处理,因为它们只是编译时常量,并且根本不会为它们分配内存:它们将被编译器替换为它们的值。

当 const 值在大小或构建时间上很昂贵时,您应该考虑手动优化的唯一情况是恕我直言。然后在头文件中声明它们是有意义的,并且只在一个翻译单元中定义它们。

如果不是这种情况,因为它们具有内部链接,这不违反单一定义规则,如果它们在不同的翻译单元中使用外部链接进行定义,则会发生这种情况。

TL/DR:在所有正常用例中,只需使用习语 an go on。如果你的内存真的短,只需控制生成的汇编代码:这些变量很可能会被优化掉并替换为它们的值。

于 2018-02-06T09:01:35.000 回答