Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 包含在许多转换单元中时静态常量的开销?_C++_Static_Header_Constants - Fatal编程技术网

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>;