[英]Is putting const before and after a function header equivalent?
[英]Putting a const in a header
从我正在阅读和测试的所有内容中,没有办法(没有预处理器宏)在共享头中定义常量,并确保每个TU不为该常量创建自己的存储。
我可以做这个:
const int maxtt=888888;
这完全相同:
static const int maxtt=888888;
如果此标头是共享的,它将起作用,但每个TU都有自己的maxtt
副本。 我也可以这样做,以防止:
extern const int maxtt;
但是我不能在这里定义maxtt
; 必须在CPP中完成,以避免链接器错误。
我的理解是否正确?
由于变量是常量,因此每个TU获得自己的副本的事实通常是无关紧要的。
在C ++中,由于这个原因,命名空间范围内的常量是隐式static
的。 通常这允许更好的代码,而不是只有一个具有外部链接的单个实例,因为(如果变量实际上是一个常量表达式),常量通常可以直接折叠到使用站点中,并且根本不需要存储。
因此,除非你真的需要获取常量的地址,或类似的东西,你应该坚持使用静态版本。 (正如你已经看到,您可以通过添加强制外部链接extern
。)另一个原因可能是,你动态初始化和只想要一个调用初始化:
// header:
extern int const n;
// one implementation:
int const n = init_function_with_side_effects();
静态构造(标头中的int const n = init();
将导致在每个TU中调用一次函数。
你写,
“从我正在阅读和测试的所有内容中,没有办法(没有预处理器宏)在共享头中定义一个常量,并确保每个TU不为该常量创建自己的存储。”
幸运的是,这是不正确的 。
对于小的积分值,您始终只需使用enum
。 权衡是你不能传递enum
值的地址,因为它没有地址。 这是纯粹的价值。
但是,为整数值节省空间是一件非常无意义的事情,因为它太小了。
所以,让我们考虑一个大事,
struct BiggyThingy
{
unsigned char zeroes[1000000];
BiggyThingy(): zeroes() {}
};
现在我们如何在头文件中声明一个BiggyThingy
常量并确保整个程序的整体常量?
最简单的是:
inline BiggyThingy const& getBiggyThingy()
{
static BiggyThingy const theThingy;
return theThingy;
}
static BiggyThingy const& biggyThingy = getBiggyThingy();
如果您不希望每个转换单元中的引用占用空间(如指针),则只需使用不带符号简化引用的函数。
这是提供常量的另一种方法,而是利用模板的特殊规则:
template< class Dummy >
class BiggyThingyConstant_
{
public:
static BiggyThingy const value;
};
template< class Dummy >
BiggyThingy const BiggyThingyConstant_<Dummy>::value;
typedef BiggyThingyConstant_<void> BiggyThingyConstant;
可以像访问一样访问
foo( BiggyThingyConstant::value )
或者,如果您需要更好的表示法,则可以为每个翻译单元添加一个引用,就像内联函数解决方案一样。
代码未受编译器影响。
但我认为你会得到这些想法。 ;-)
仅当您应用任何需要常量地址的操作时,此代码才会在TU中生成常量。
static int maxtt = 888888;
int * pmaxtt = &maxtt; //address of constant requested.
这也可以工作并避免链接器问题(尽管如果请求地址, maxtt
在每个TU中存储maxtt
):
constexpr int maxtt = 888888;
避免extern
结构,因为它无法优化。
如果您对存储非常担心,请使用枚举:
enum { maxtt = 888888 };
枚举器是标量右值,因此不需要存储。 说&maxtt
是违法的。
实际上,您对语义的理解是正确的。
实际上,每个翻译单元可能无法获得整数的存储副本。 一个原因是编译器可能会将值实现为文本,只要它被引用。 链接器也可能足够聪明,如果发现它未被引用,则丢弃该存储。
编译器可能无法为常量使用文字。 您可以引用该整数,或获取指向它的指针。 在这种情况下,您需要存储 - 您甚至可能需要交叉compiland唯一性。 如果在每个编译单元中获取const
符号的地址,您可能会发现它的不同,因为每个对象都将获得唯一的静态副本。
如果使用枚举,可能会遇到类似的问题; 你的const int
有存储空间,你可以获取该存储的地址。 在将其存储到某个位置之前,您无法获取枚举的地址。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.