假设我有一个头文件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
默认为C++
,internal linkage
),他们“驻留”在翻译单元的范围内。
现在,假设我将这些文件包含10次到我的应用程序中(来自10个不同的.cpp
)。
当我编译时,会创建一个目标文件,并且(稍后)链接器会将所有这些目标文件一起收集到一个唯一的可运行代码中。
这是否意味着当我run
程序时,它将在内存中分配10次以上的每个结构?即10x5结构?
所以即使它们之后被链接在一起,它们对于翻译单元也是分开的?或者链接器是否足够聪明,可以将它们收敛到内存中的唯一分配?
不确定我是否巧妙地完成了这些步骤。我喜欢C ++中的新东西。
答案 0 :(得分:1)
是。但是(1)少数字节与最小的可执行文件的通常大小无关,而且(2)无论如何它都可能被优化掉。如果你想避免这种情况,请使用constexpr
,这使得它们只编译时间值。
在其他新闻中,C ++中的一个常见约定是仅使用宏的所有大写标识符。这是因为所有大写都是眼睛,因此惯例应该保留给那些通常也不好的东西。当你使用全部大写的任何其他东西时,你(1)似乎对许多程序员大喊大叫,(2)冒险无意中文本替换,以及(3)冒错误传达这些名称所代表的内容。
C ++不是Java或Python。
这些语言得到了早期C常量的大写约定,它没有const
,因此它们必须将常量表示为预处理器宏。即,Java和Python约定实际上是来自C的大写宏规则。在C ++中使用常量宏是过时的,并且与这些语言不同,C ++确实有预处理器。
另外,请注意:类型的前缀I
是指示(抽象)接口的常用约定,但根据您的声明IColor
必须是具体的,可实例化的类型。
答案 1 :(得分:0)
请记住:标准仅指定抽象机器的行为。模拟抽象机器不需要实际实现,只需要模拟其可观察行为。
因此抽象机器的 每个内部链接变量的实例将按照翻译单元进行分配。但由于它们是常量,很可能您只使用它们的值而不是它们的地址 - 在标准术语中它们可能不会被使用(一个定义规则)。在这种情况下,它们将由编译器处理,因为它们只是编译时常量,并且根本不会为它们分配任何内存:它们将由编译器替换它们的值。
当const值的大小或构造时间昂贵时,唯一应该考虑手动优化的情况是恕我直言。然后在标题中声明它们是extern,并且只在一个转换单元中定义它们。
如果不是这样,因为它们具有内部联系,这不违反一个定义规则,如果它们是在不同的翻译单元中使用外部链接定义的话。
TL / DR:在所有正常使用案例中,只需使用成语即可。如果你真的非常内存不足,只需控制生成的汇编代码:这些变量可能会被优化掉并替换为它们的值。
答案 2 :(得分:0)
您可能在编译阶段有10个,但最终可能会在链接阶段进行优化。
但是,您可以尝试使用不同的方法来处理这种常量变量定义,以防由于某些内存限制而需要确定。
拥有头文件,只将变量声明放在extern
。
// my_consts.h
extern const IColor COLOR_BLACK;
然后创建一个显示实际定义的源文件。
// my_consts.cpp
const IColor COLOR_BLACK(255, 0, 0, 0);
这样实际的定义只编译一次,你仍然可以引用它们,因为你已经在头文件中声明了它们。
此外,有了这样的常量,将它们粘贴到某个命名空间以避免全局命名空间污染会很好 - 特别是如果你可以将它们划分为某些逻辑类别。