1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
|
---
title: static vs. inline vs. namespace {
category: C++
snippets_root_directory: snippets/static_vs_inline_vs_unnamed_namespaces
snippets_language: c++
snippets:
static:
- static/main.cpp
- static/proxy.cpp
- static/proxy.hpp
- static/shared.hpp
inline:
- inline/shared.hpp
inline_weird:
- inline/weird/main.cpp
- inline/weird/another.cpp
- inline/weird/another.hpp
unnamed_namespaces_weird:
- unnamed_namespaces/weird/main.cpp
- unnamed_namespaces/weird/another.cpp
- unnamed_namespaces/weird/another.hpp
unnamed_namespaces_ok:
- unnamed_namespaces/ok/main.cpp
- unnamed_namespaces/ok/another.cpp
- unnamed_namespaces/ok/another.hpp
static_and_inline:
- static_and_inline/main.cpp
- static_and_inline/proxy.cpp
- static_and_inline/proxy.hpp
- static_and_inline/shared.hpp
unnamed_namespace_and_inline:
- unnamed_namespace_and_inline/main.cpp
- unnamed_namespace_and_inline/proxy.cpp
- unnamed_namespace_and_inline/proxy.hpp
- unnamed_namespace_and_inline/shared.hpp
separate_method_definitions:
- separate_method_definitions/main.cpp
- separate_method_definitions/another.cpp
- separate_method_definitions/another.hpp
- separate_method_definitions/shared.hpp
---
In this post I'll try to figure out whether I should use `static`, `inline` or
unnamed namespaces for function definitions.
TL;DR
-----
Here's my attempt to build an algorithm to decide whether a class/function
should be defined with either of the `static`/`inline` specifiers or put into
an unnamed namespace.
The first question I answer is: is the entity defined in a header file or in a
.cpp file?
* **In a header** — Is it a class or a function?
* **Class** — There's no need to do anything.
* **Function** — Do you want it to behave differently for each
translation unit (may be useful, for example, for logging)?
* **Yes** — Use `static`.
* **No** — Use `inline`.
* **In a .cpp file** — Put it into an unnamed namespace.
`static`
--------
It's an old C-style method of defining functions in header files.
This way, every translation unit gets its own copy of a function.
What does that mean?
The most obvious implication that pops into my head is that every local static
variable defined inside that function gets an independent replica in every
translation unit.
For example, the program below would print
```
1
1
```
due to the fact that both main.cpp and proxy.cpp get their own versions of `n`
from `shared()`.
{% include jekyll-theme/snippets/section.html section_id='static' %}
In C, this is the only way to share function definitions between translation
units (apart from the usual way of declaring a function in a header file and
putting its definition to a .c file).
### Properties
* Using `static`, you can share function definitions between multiple
translation units.
* Each unit gets its own replica of the function: they have different
addresses, their local static variables are independent, etc.
* If different translation units define different functions with the same
name using the `static` specifier, each unit can use its function without any
issues.
This might seem like an trivial claim, but other approaches sometimes disallow
this, which is discussed below.
`inline`
--------
It's well-known that this keyword has pretty much nothing to do with whether a
function will actually be inlined or not.
It's used much more often to define functions in header files, since every
function defined this way will be the same (as in "will have the same address")
in every translation unit.
Let's try and adjust the definition of `shared()` accordingly:
{% include jekyll-theme/snippets/section.html section_id='inline' %}
The same program would then print
```
1
2
```
since both `main()` and `proxy()` would call the same `shared()`, incrementing
the same `n`.
Weird things happen when different translation units define different `inline`
functions with the same name.
{% include jekyll-theme/snippets/section.html section_id='inline_weird' %}
According to my simple experiments, this program produces different output
based on which .cpp file was specified first on the command line during
compilation.
For example, this is the output of test.exe produced with either `cl /W4 /EHsc
main.cpp another.cpp /Fe:test.exe` or `g++ -Wall -Wextra -std=c++11 main.cpp
another.cpp -o test.exe`.
```
main.cpp: shared()
main.cpp: shared()
```
If we swap the order of .cpp files (`another.cpp main.cpp` instead of `main.cpp
another.cpp`), the output becomes
```
another.cpp: shared()
another.cpp: shared()
```
No warnings/errors are emitted, making the situation truly disturbing.
I tested this with GNU compiler version 5.4.0 and Microsoft compiler version
19.00.24210.
This behavior can be easily fixed either by making these functions `static` or
by using unnamed namespaces (see below).
### Properties
* Using `inline`, you can share function definitions between multiple
translation units.
* Each translation unit will use the same function: it will have the same
address in every translation unit, its local static variables will be shared,
etc.
* Defining different `inline` functions with the same name in different
translation units is undefined behavior.
Two inline functions might be different even if they are the same textually.
For example, they might reference two global variables which have the same
name, but are defined in different translation units.
{: .alert .alert-info }
`namespace {`
-------------
With respect to function definitions, unnamed namespaces are, according to my
understanding, quite similar to the `static` keyword.
The additional value they provide is that they provide a way to apply `static`
not only to functions, but to classes also.
Remember the weirdness that happens when multiple translation units define
different `inline` functions with the same name?
Arguably, it gets even worse if we add classes to the equation.
{% include jekyll-theme/snippets/section.html section_id='unnamed_namespaces_weird' %}
Compiling this program the same way we did in the `inline` example (`cl /W4
/EHsc main.cpp another.cpp /Fe:test.exe`/`g++ -Wall -Wextra -std=c++11 main.cpp
another.cpp -o test.exe`) yields different outputs depending on which .cpp file
was specified first.
```
main.cpp: Test::Test()
1
main.cpp: Test::Test()
```
```
another.cpp: Test::Test()
1065353216
another.cpp: Test::Test()
```
I'm not sure why anybody would want that.
This can be easily fixed by putting both `Test` classes into unnamed
namespaces.
The program than reads
{% include jekyll-theme/snippets/section.html section_id='unnamed_namespaces_ok' %}
After the adjustment, it produces the same output regardless of compilation
options.
```
main.cpp: Test::Test()
1
another.cpp: Test::Test()
```
Notice how sharing classes defined in header files isn't discussed here.
The standard actually guarantees that if a class is defined in a header file,
all translation units that use it share the definition.
### Properties
* Essentially, unnamed namespaces allow the `static` keyword to be applied to
classes.
* Similar to the `static` approach, each translation unit gets its own replica
of a function/class, including their own local static variables, etc.
* Defining different classes with the same name in different translation units
(without utilizing unnamed namespaces) is undefined behavior.
Tricky cases
------------
### `static` + `inline`
In case a function is defined as `static inline`, `static` wins, and `inline`
is ignored.
The program below outputs
```
1
1
```
{% include jekyll-theme/snippets/section.html section_id='static_and_inline' %}
In general, I can't think of a reason to define a `static inline` function.
### `namespace {` + `inline`
If an `inline` function is defined in an unnamed namespace, the unnamed
namespace wins.
The program below outputs
```
1
1
```
{% include jekyll-theme/snippets/section.html section_id='unnamed_namespace_and_inline' %}
In general, I can't think of a reason to define an `inline` function in an
unnamed namespace.
### Separate method definitions
If you want to separate your class declaration from its method definitions
while keeping them in the same header file, each method must be explicitly
defined `inline`.
The program below outputs
```
1
2
```
{% include jekyll-theme/snippets/section.html section_id='separate_method_definitions' %}
|