C++ 包含在许多转换单元中时静态常量的开销?
在头文件中,可以在一行中声明和(预定义)全局常量C++ 包含在许多转换单元中时静态常量的开销?,c++,static,header,constants,C++,Static,Header,Constants,在头文件中,可以在一行中声明和(预定义)全局常量 // constants.h namespace Constant{ static const unsigned int framerate = 60; static const char * const windowName = "Test"; static const unsigned char * const cursorBitmap = { lots of data }; } 我喜欢这种格式,因为它允许我将常量保
// constants.h
namespace Constant{
static const unsigned int framerate = 60;
static const char * const windowName = "Test";
static const unsigned char * const cursorBitmap = { lots of data };
}
我喜欢这种格式,因为它允许我将常量保存在一个地方,并且避免了在一个文件中声明常量和在另一个文件中定义常量,这有助于提高可读性。但是,当任何翻译单位包含常量.h
时,它会按单位展开这些定义
我的问题是,如果我将常量.h
包含到许多转换单元中,例如,cursorBitmap
和其他数组常量都非常大,这会导致很大的开销吗?如果我将每个字符串和数组文本包含到100个单元中,那么我的程序是否会包含100个副本?还是只复制指针和值
如果有开销,有没有一种方法可以避免它而不需要单独声明和定义
(我猜在这种用法中“static”是多余的,但我还是想把它放在那里)字符串文本是否在不同的翻译单元中重复是一个实现质量问题 直接声明的对象将在包含此标题的每个翻译单元中复制。不过不多。在一个转换单元中,某个常量的地址没有直接或间接使用,它可能会被优化掉 如果要确保每个常量只有一个副本,甚至没有副本,则可以使用类模板,如下所示: 常数.h
#pragma一次
模板
结构常数_{
静态常量无符号整数帧率;
静态常量字符*常量窗口名;
静态常量无符号字符*常量cursorBitmap;
};
模板
常量无符号整型常量u3;::帧速率=60;
模板
常量字符*常量常量_
常量无符号字符*常量常量_u3;::cursorBitmap=。。。;
使用常数=常数;
但我做的工作太多了
类似的替代方法是使用
内联
函数,每个常量一个。首先,在命名空间中使用静态
是不推荐的,因为C++98:
D.2静态
关键字在命名空间范围内声明对象时,不推荐使用
static
关键字(参见3.3.5)
第二,代码> const <代码>暗示C++内部链接本身。
第三,确切答案取决于编译器和您使用的选项。编译器/链接器可以消除重复,特别是在可以使用LTO(链接时间优化)的情况下 如果我将每个字符串和数组文本包含到100个单元中,那么我的程序是否会包含100个副本?还是只复制指针和值 该标准不承诺合并字符串文本,因此由实现决定。在GNU/Linux上使用GCC 5.1.1进行的一个简单测试表明,字符串文本不会在未优化的版本中合并,而是在使用-O
或-Os
时合并。但这只是合并实际的char
数组。如果编译器没有优化指针或数值常量的存储(如果它们是翻译单元本地的,没有使用ODR,并且是POD类型,它们显然是根据“如同”规则消除的候选者),那么编译器可能无法轻松合并它们。标准要求它们是不同的对象,因此必须有不同的地址。“仿佛”规则可能仍然允许删除它们,即使您要获取它们的地址,但这通常需要全局程序优化(也称为链接时间优化),包括实现可能不支持的库、仅以有限方式支持的库和/或仅取决于编译器和链接器设置的库。换句话说,它可能只是在适当的情况下发生,但更可能不会发生
我自己的测试表明,GCC 5.1.1不会合并由const
ref公开的static const unsigned int
对象,即使使用-Os-flto
(优化大小并启用链接时间优化)。坦率地说,如果任何当代实现确实执行了这种困难而模糊的优化,我会感到惊讶
(另外,我猜“static”在这种用法中是多余的,但我还是喜欢把它放在那里)
如果您有多个翻译单元,这并不是多余的,因为否则您将违反一个定义规则(ODR)。但是,作为一个补充说明,命名空间范围内的静态在语法上已经过时很长时间了(请考虑使用匿名命名空间,这是在C++98中引入的)
(回应欢呼声和hth.-Alf)
如果要确保每个常量只有一个副本,甚至没有副本,则可以使用类模板,如下所示:
没有这样的运气。标准中没有保证模板使用了多少空间。该模板所能保证的是,根据“似乎”规则,可能使用的多个副本中,只有一个被使用,或者似乎被使用。事实上,它比这更糟糕,因为至少GCC 5.1.1实际上没有删除冗余的
静态常量unsigned int
,即使在我的系统上使用-Os-flto
。这意味着对于两个转换单元,无符号int
的初始值设定值可以在两个单独的位置找到,即使只使用其中一个位置(所有指针和引用仅指此位置)。TU与最终链接的二进制文件有何关联?“如果我将每个字符串和数组文本包含在100个单元中,那么我的程序会包含100个副本吗?”非静态的情况如何?@xaxxon:库和程序是两种截然不同的东西。这个问题是关于一个节目的。普通图书馆是翻译单位的集合,可以单独使用,也可以集体使用
#pragma once
template< class Dummy >
struct Constant_{
static const unsigned int framerate;
static const char * const windowName;
static const unsigned char * const cursorBitmap;
};
template< class Dummy >
const unsigned int Constant_<Dummy>::framerate = 60;
template< class Dummy >
const char * const Constant_<Dummy::windowName = "Test";
template< class Dummy >
const unsigned char * const Constant_<Dummy>::cursorBitmap = ...;
using Constant = Constant_<void>;