Overhead of static constants when they are included in many translation units?

In the header file, global constants can be declared and (pre) defined on one line.

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

I like this format because it allows me to save constants in one place and avoid the need to declare a constant in one file and define it in another, helping readability. However, if any translation unit includes constants.h , it extends these definitions in place by one.

My question is, will this lead to significant overhead if I include constants.h in many translation units and, for example, cursorBitmap , and other array constants are significantly large? Will my program contain 100 copies of each line and array literal if I include it in 100 units? Or will only pointers and values ​​be copied?

If there is overhead, is there a way to avoid this without requiring a separate declaration and definition?

(I also assume that β€œstatic” is redundant in this use, but I like it there anyway)

+6
source share
3 answers

Whether string literals will be repeated in different units of translation is a quality issue.

Directly declared objects will be duplicated in each translation unit, where this header is included. It's not that much. And in the translation block, where some permanent address is not directly or indirectly used, it can be optimized.

If you want to provide only one copy of each constant or even no copy, you can use a template template, for example:

<i> constants.h
 #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>; 

But this is IMHO more work than it costs.

A similar alternative is to use inline functions, one for each constant.

+3
source

Will my program contain 100 copies of each row and array if I include it in 100 units? Or will only pointers and values ​​be copied?

The standard does not promise the consolidation of string literals, so before implementation. A simple test using GCC 5.1.1 on GNU / Linux showed that string literals are not combined into an unoptimized assembly, but are consolidated using -O or -Os . But this is just a merge of real char arrays. To the extent that the compiler does not optimize storage for a pointer or for numeric constants (if they are local to the translation unit and not to ODR and POD type, they are obvious candidates for elimination according to as-if), however, the compiler may not be able to easily consolidate them. The standard requires that they be different objects and, therefore, must have different addresses. The as-if rule can still allow them to be deleted even if you have to accept their addresses, but this usually requires global optimization of the programs, as well as optimization of connection time, including libraries that the implementation may not support, only support in a limited way, / or only depending on the compiler and linker settings. In other words, this can happen under the right circumstances, but it is much more likely that this will not happen.

My own test shows that GCC 5.1.1 does not combine static const unsigned int objects exposed by const ref, even with -Os -flto (optimize size and enable bind time optimization). I would be frankly surprised if some modern implementation really performed this complex and obscure optimization.

(I also assume that β€œstatic” is redundant in this use, but I like it there anyway)

This is not redundant if you have several translation units, because otherwise you could work with one definition rule (ODR). However, as a side note, the static in the namespace has been considered syntactically obsolete for a long time (consider using anonymous namespaces introduced in C ++ 98).

(in response to Cheers and hth. - Alf)

If you want to provide only one copy of each constant or even no copy, you can use a template template, for example:

There is no such luck. There is no guarantee in the standard how much space is used for templates. The entire template ensures that only one of the potentially many copies is used - or, apparently, used according to the as-if rule. This is actually worse because at least GCC 5.1.1 does not actually remove the excess static const unsigned int even with -Os -flto on my system. This means that with two translation units, the initializer value for unsigned int can be found in two different places, although only one of them is used (all pointers and links refer only to this location).

+1
source

Firstly, the use of static in the namespace is deprecated since C ++ 98:

D.2 static keyword
The use of the static is deprecated when declaring objects in the namespace area (see Section 3.3.5)

Secondly, const implies internal communication in C ++ independently.

Thirdly, the exact answer depends on the compiler you are using and the parameters. Duplicates can be eliminated by the compiler / linker, especially if you use LTO (Link Time Optimization).

0
source

All Articles