aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md
diff options
context:
space:
mode:
Diffstat (limited to '_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md')
-rw-r--r--_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md279
1 files changed, 0 insertions, 279 deletions
diff --git a/_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md b/_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md
deleted file mode 100644
index 4cb0960..0000000
--- a/_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md
+++ /dev/null
@@ -1,279 +0,0 @@
----
-title: static vs. inline vs. namespace {
-excerpt: >
- Should I use `static`, `inline` or unnamed namespaces for function
- definitions?
-category: C++
-custom_css:
- - snippets.css
- - syntax.css
-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.
-
-`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 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 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 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 behaviour 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 behaviour.
-
-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 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 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 behaviour.
-
-Conclusion
-----------
-
-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.
-
-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 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 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 snippets/section.html section_id='separate_method_definitions' %}