From adb9b3fe169a92ea2da7b8c804c8b91f966c21a4 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Thu, 7 May 2020 01:48:11 +0000 Subject: remove everything except Jekyll theme stuff I tagged the previous commit to explain what's going on. --- _posts/2015-07-03-std-call-once-bug.md | 258 ------------------- _posts/2017-01-07-building-boost.md | 248 ------------------ ...06-24-static-vs-inline-vs-unnamed-namespaces.md | 279 --------------------- _posts/2018-02-18-peculiar-indentation.md | 106 -------- _posts/2019-09-30-recurring-decimals.md | 93 ------- _posts/2020-02-24-ssh-tunnel-windows.md | 154 ------------ _posts/2020-05-06-docker-bind-mounts.md | 176 ------------- .../inline/shared.hpp | 6 - .../inline/weird/another.cpp | 11 - .../inline/weird/another.hpp | 3 - .../inline/weird/main.cpp | 13 - .../separate_method_definitions/another.cpp | 6 - .../separate_method_definitions/another.hpp | 3 - .../separate_method_definitions/main.cpp | 8 - .../separate_method_definitions/shared.hpp | 12 - .../static/main.cpp | 10 - .../static/proxy.cpp | 6 - .../static/proxy.hpp | 3 - .../static/shared.hpp | 6 - .../static_and_inline/main.cpp | 10 - .../static_and_inline/proxy.cpp | 6 - .../static_and_inline/proxy.hpp | 3 - .../static_and_inline/shared.hpp | 6 - .../unnamed_namespace_and_inline/main.cpp | 10 - .../unnamed_namespace_and_inline/proxy.cpp | 6 - .../unnamed_namespace_and_inline/proxy.hpp | 3 - .../unnamed_namespace_and_inline/shared.hpp | 10 - .../unnamed_namespaces/ok/another.cpp | 19 -- .../unnamed_namespaces/ok/another.hpp | 3 - .../unnamed_namespaces/ok/main.cpp | 22 -- .../unnamed_namespaces/weird/another.cpp | 15 -- .../unnamed_namespaces/weird/another.hpp | 3 - .../unnamed_namespaces/weird/main.cpp | 18 -- 33 files changed, 1535 deletions(-) delete mode 100644 _posts/2015-07-03-std-call-once-bug.md delete mode 100644 _posts/2017-01-07-building-boost.md delete mode 100644 _posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md delete mode 100644 _posts/2018-02-18-peculiar-indentation.md delete mode 100644 _posts/2019-09-30-recurring-decimals.md delete mode 100644 _posts/2020-02-24-ssh-tunnel-windows.md delete mode 100644 _posts/2020-05-06-docker-bind-mounts.md delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/shared.hpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.cpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.hpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/main.cpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.cpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.hpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/main.cpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/shared.hpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/main.cpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.cpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.hpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/shared.hpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/main.cpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.cpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.hpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/shared.hpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/main.cpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.cpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.hpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/shared.hpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.cpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.hpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/main.cpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.cpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.hpp delete mode 100644 _posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/main.cpp (limited to '_posts') diff --git a/_posts/2015-07-03-std-call-once-bug.md b/_posts/2015-07-03-std-call-once-bug.md deleted file mode 100644 index 0aa0249..0000000 --- a/_posts/2015-07-03-std-call-once-bug.md +++ /dev/null @@ -1,258 +0,0 @@ ---- -title: std::call_once bug in Visual C++ 2012/2013 -excerpt: > - In this post I will describe a nasty bug I've stumbled upon in the C++ - Standard Library implementation shipped with Microsoft Visual Studio - 2012/2013. -category: C++ -custom_css: - - syntax.css ---- -I've recently come across a nasty standard library bug in the implementation -shipped with Microsoft Visual Studio 2012/2013. -[StackOverflow was of no help], so I had to somehow report the bug to the -maintainers. -Oddly enough, Visual Studio's [Connect page] wouldn't let me report one, -complaining about the lack of permissions, even though I was logged in from my -work account, associated with my Visual Studio 2013 installation. - -Fortunately, I've come across the personal website of this amazing guy, -[Stephan T. Lavavej], who appears to be the chief maintainer of Microsoft's -standard library implementation. -He seems to be your go-to guy when it comes to obvious standard library -misbehaviours. - -[StackOverflow was of no help]: https://stackoverflow.com/questions/26477070/concurrent-stdcall-once-calls -[Connect page]: https://connect.microsoft.com/VisualStudio -[Stephan T. Lavavej]: http://nuwen.net/stl.html - -C++11 and singletons --------------------- - -Anyway, the story begins with me trying to implement the singleton pattern -using C++11 facilities like this: - -```c++ -#include - -template -class Singleton { -public: - static Derived& get_instance() { - std::call_once(initialized_flag, &initialize_instance); - return Derived::get_instance_unsafe(); - } - -protected: - Singleton() = default; - ~Singleton() = default; - - static Derived& get_instance_unsafe() { - static Derived instance; - return instance; - } - -private: - static void initialize_instance() { - Derived::get_instance_unsafe(); - } - - static std::once_flag initialized_flag; - - Singleton(const Singleton&) = delete; - Singleton& operator=(const Singleton&) = delete; -}; - -template -std::once_flag Singleton::initialized_flag; -``` - -Neat, huh? -Now other classes can inherit from `Singleton`, implementing the singleton -pattern effortlessly: - -```c++ -class Logger : public Singleton { -private: - Logger() = default; - ~Logger() = default; - - friend class Singleton; -}; -``` - -Note that the [N2660] standard proposal isn't/wasn't implemented in the -compilers shipped with Visual Studio 2012/2013. -If it was, I wouldn't, of course, need to employ this `std::call_once` -trickery, and the implementation would be much simpler, i.e. something like -this: - -```c++ -class Logger { -public: - static Logger& get_instance() { - static Logger instance; - return instance; - } - -private: - Logger() = default; - ~Logger() = default; -}; -``` - -
- -The point is that the `Logger::get_instance` routine above wasn't thread-safe -until C++11. -Imagine what might happen if `Logger`'s constructor takes some time to -initialize the instance. -If a couple of threads then call `get_instance`, the first thread might begin -the initialization process, making the other thread believe that the instance -had already been intialized. -This other thread might then return a reference to the instance which hasn't -yet completed its initialization and is most likely unsafe to use. - -Since C++11 includes the proposal mentioned above, this routine would indeed be -thread-safe in C++11. -Unfortunately, the compilers shipped with Visual Studio 2012/2013 don't/didn't -implement this particular proposal, which caused me to look at -`std::call_once`, which seemed to implement exactly what I needed. - -
- -[N2660]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm - -Problem -------- - -Unfortunately, matters became a bit more complicated when I tried to introduce -two singletons, one having a dependency on the other. -I had `Logger`, like in the example above, and some kind of a "master" -singleton (let's call it `Duke`). -`Duke`'s constructor was complicated and time-consuming, and definetely -required some logging to be done. -I thought that I could simply call `Logger::get_instance` inside `Duke`'s -constructor, and everything looked fine at first glance. - -```c++ -#include -#include - -class Logger : public Singleton { -public: - Logger& operator<<(const char* msg) { - // Actual logging is stripped for brevity. - return *this; - } - -private: - Logger() { - // Opening log files, etc. - std::this_thread::sleep_for(std::chrono::seconds{3}); - } - - ~Logger() = default; - - friend class Singleton; -}; - -class Duke : public Singleton { -private: - Duke() { - Logger::get_instance() << "started Duke's initialization"; - // It's a lot of work to be done. - std::this_thread::sleep_for(std::chrono::seconds{10}); - Logger::get_instance() << "finishing Duke's initialization"; - } - - ~Duke() = default; - - friend class Singleton; -}; -``` - -Now, what happens if I have two threads, one using the `Duke` instance, and the -other logging something? -Like in this example: - -```c++ -#include - -namespace { - -void get_logger() { - entered(__FUNCTION__); - Logger::get_instance(); - exiting(__FUNCTION__); -} - -void get_duke() { - entered(__FUNCTION__); - Duke::get_instance(); - exiting(__FUNCTION__); -} - -} - -int main() { - std::thread t1{&get_duke}; - std::thread t2{&get_logger}; - t1.join(); - t2.join(); - return 0; -} -``` - -`entered` and `exiting` are utility functions to print timestamps. -The implementation is included in the [complete code sample]. -{: .alert .alert-info } - -The first thread is supposed to have the total running time of about 13 -seconds, right? -Three seconds to initialize the `Logger` instance and ten to initialize the -`Duke` instance. -The second thread, similarly, is supposed to be done in about 3 seconds -required for the initialization of `Logger`. - -Weirdly, this program produces the following output when compiled using Visual -Studio 2013's compiler: - - Entered `anonymous-namespace'::get_duke at Fri Jul 03 02:26:16 2015 - Entered `anonymous-namespace'::get_logger at Fri Jul 03 02:26:16 2015 - Exiting `anonymous-namespace'::get_duke at Fri Jul 03 02:26:29 2015 - Exiting `anonymous-namespace'::get_logger at Fri Jul 03 02:26:29 2015 - -Isn't it wrong that the second thread actually took the same 13 seconds as the -first thread? -Better check with some other compiler in case it was me who made a mistake. -Unfortunately, the program behaves as expected when compiled using GCC: - - Entered get_logger at Fri Jul 3 02:27:12 2015 - Entered get_duke at Fri Jul 3 02:27:12 2015 - Exiting get_logger at Fri Jul 3 02:27:15 2015 - Exiting get_duke at Fri Jul 3 02:27:25 2015 - -So it appears that the implementation of `std::call_once` shipped with Visual -Studio 2012/2013 relies on some kind of a global lock, which causes even the -simple example above to misbehave. - -The [complete code sample] to demonstrate the misbehaviour described above can -be found in this blog's repository. - -[complete code sample]: {{ site.github.repository_url }}/tree/master/std_call_once_bug - -Resolution ----------- - -So, since I couldn't submit the bug via Visual Studio's [Connect page], I wrote -to Mr. Lavavej directly, not hoping for an answer. -Amazingly, it took him less than a day to reply. -He told me he was planning to overhaul `std::call_once` for Visual Studio 2015. -Meanwhile, I had to stick to something else; I think I either dropped logging -from `Duke`'s constructor or initialized all the singleton instances manually -before actually using any of them. -In a few months, Mr. Lavavej replied to me that the bug has been fixed in -Visual Studio 2015 RTM. -I would like to thank him for the professionalism and responsibility he's -shown. diff --git a/_posts/2017-01-07-building-boost.md b/_posts/2017-01-07-building-boost.md deleted file mode 100644 index 052bb26..0000000 --- a/_posts/2017-01-07-building-boost.md +++ /dev/null @@ -1,248 +0,0 @@ ---- -title: Building Boost on Windows -excerpt: > - This post describes the process of building Boost on Windows using either - Visual Studio or the combination of Cygwin + MinGW-w64. -category: C++ -custom_css: - - syntax.css ---- -Below you can find the steps required to build Boost libraries on Windows. -These steps tightly fit my typical workflow, which is to use Boost libraries in -CMake builds using either Visual Studio or the combination of Cygwin + -MinGW-w64. -I would expect, however, that the procedure for the latter toolset can easily -be adjusted for generic GCC distributions (including vanilla GCCs found in -popular Linux distributions). - -One of the features of this workflow is that I build throwaway, "run -everywhere, record the results, and scrap it" executables more often than not, -so I prefer to link everything statically, including, for instance, C/C++ -runtimes. -This is implemented by passing `runtime-link=static` to Boost's build utility -`b2`; change this to `runtime-link=dynamic` to link the runtime dynamically. - -Excerpts from shell sessions in this post feature a few different commands -besides Boost's `b2` and `cmake`, like `cd` and `cat`. -They are used to hint at my personal directory layout, display various -auxiliary files, etc. -Windows' `cd`, for example, simply prints the current working directory; -Cygwin's `pwd` serves the same purpose. -`cat` is used to display files. -Windows' command prompts are denoted with `>`s at the beginning of each line; -Cygwin's — with `$`s. - -Visual Studio -------------- - -Statically-linked Boost libraries are built, both the debug and the release -versions of them (these are default settings). -While it is required to keep x86 and x64 libraries in different directories (to -avoid file name clashes), it's not necessary to separate debug libraries from -their release counterparts, because that information is actually encoded in -file names (the "gd" suffix). - -### x86 - -``` -> cd -D:\workspace\third-party\boost_1_61_0\msvc - -> bootstrap -... - -> b2 --stagedir=stage\x86 ^ - runtime-link=static ^ - --with-filesystem ^ - --with-program_options ^ - ... -... -``` - -### x64 - -The only important difference is that you have to pass `address-model=64` to -`b2` (notice also the different "staging" directory). - -``` -> cd -D:\workspace\third-party\boost_1_61_0\msvc - -> bootstrap -... - -> b2 --stagedir=stage\x64 ^ - runtime-link=static ^ - address-model=64 ^ - --with-filesystem ^ - --with-program_options ^ - ... -... -``` - -Cygwin + MinGW-w64 ------------------- - -Contrary to the Visual Studio example above, it is required to store debug and -release libraries *as well as* x86 and x64 libraries in different directories. -It is required to avoid file name clashes; unlike the Visual Studio "toolset" -(in Boost's terms), GCC-derived toolsets don't encode any information (like -whether the debug or the release version of a library was built) in file names. - -Also, linking the runtime statically doesn't really make sense for MinGW, as it -always links to msvcrt.dll, which is [simply the Visual Studio 6.0 runtime]. - -[simply the Visual Studio 6.0 runtime]: https://sourceforge.net/p/mingw-w64/wiki2/The%20case%20against%20msvcrt.dll/ - -In the examples below, only the debug versions of the libraries are built. -Build the release versions by executing the same command, and substituting -`variant=release` instead of `variant=debug` and either -`--stagedir=stage/x86/release` or `--stagedir=stage/x64/release`, depending -on the target architecture. - -### x86 - -``` -$ pwd -/cygdrive/d/workspace/third-party/boost_1_61_0/mingw - -$ ./bootstrap.sh -... - -$ cat user-config-x86.jam -using gcc : : i686-w64-mingw32-g++ ; - -$ ./b2 toolset=gcc-mingw \ - target-os=windows \ - link=static \ - variant=debug \ - --stagedir=stage/x86/debug \ - --user-config=user-config-x86.jam \ - --with-filesystem \ - --with-program_options \ - ... -... -``` - -The "user" configuration file above stopped working at some point; not sure as -to who's to blame, Cygwin or Boost. -If you see something like "`error: provided command 'i686-w64-mingw32-g++' not -found`", add ".exe" to the binary name above, so that the whole file reads -"`using gcc : : i686-w64-mingw32-g++.exe ;`". -{: .alert .alert-info } - -### x64 - -Notice the two major differences from the x86 example: - -* the addition of `address-model=64` (as in the example for Visual Studio), -* the different "user" configuration file, pointing to `x86_64-w64-mingw32-g++` -instead of `i686-w64-mingw32-g++`. - -Again, as in the example for Visual Studio, a different "staging" directory -needs to be specified using the `--stagedir` parameter. - -``` -$ cd -/cygdrive/d/workspace/third-party/boost_1_61_0/mingw - -$ ./bootstrap.sh -... - -$ cat user-config-x64.jam -using gcc : : x86_64-w64-mingw32-g++ ; - -$ ./b2 toolset=gcc-mingw \ - address-model=64 \ - target-os=windows \ - link=static \ - variant=debug \ - --stagedir=stage/x64/debug \ - --user-config=user-config-x64.jam \ - --with-filesystem \ - --with-program_options \ - ... -... -``` - -The "user" configuration file above stopped working at some point; not sure as -to who's to blame, Cygwin or Boost. -If you see something like "`error: provided command 'x86_64-w64-mingw32-g++' -not found`", add ".exe" to the binary name above, so that the whole file reads -"`using gcc : : x86_64-w64-mingw32-g++.exe ;`". -{: .alert .alert-info } - -Usage in CMake --------------- - -### Visual Studio - -Examples below apply to Visual Studio 2015. -You may want to adjust the paths. - -#### x86 - -``` -> cd -D:\workspace\build\test_project\msvc\x64 - -> cmake -G "Visual Studio 14 2015" ^ - -D BOOST_ROOT=D:\workspace\third-party\boost_1_61_0\msvc ^ - -D BOOST_LIBRARYDIR=D:\workspace\third-party\boost_1_61_0\msvc\stage\x86\lib ^ - -D Boost_USE_STATIC_LIBS=ON ^ - -D Boost_USE_STATIC_RUNTIME=ON ^ - ... -``` - -#### x64 - -``` -> cd -D:\workspace\build\test_project\msvc\x86 - -> cmake -G "Visual Studio 14 2015 Win64" ^ - -D BOOST_ROOT=D:\workspace\third-party\boost_1_61_0\msvc ^ - -D BOOST_LIBRARYDIR=D:\workspace\third-party\boost_1_61_0\msvc\stage\x64\lib ^ - -D Boost_USE_STATIC_LIBS=ON ^ - -D Boost_USE_STATIC_RUNTIME=ON ^ - ... -``` - -### Cygwin & MinGW-w64 - -Examples below only apply to debug CMake builds. -Notice that, contrary to the Visual Studio examples above, debug and release -builds must be kept in separate directories. -You may also want to adjust the paths. - -#### x86 - -``` -$ pwd -/cygdrive/d/workspace/build/test_project/mingw/x86/debug - -$ cmake -G "Unix Makefiles" \ - -D CMAKE_BUILD_TYPE=Debug \ - -D CMAKE_C_COMPILER=i686-w64-mingw32-gcc \ - -D CMAKE_CXX_COMPILER=i686-w64-mingw32-g++ \ - -D BOOST_ROOT=/cygdrive/d/workspace/third-party/boost_1_61_0/mingw \ - -D BOOST_LIBRARYDIR=/cygdrive/d/workspace/third-party/boost_1_61_0/mingw/stage/x86/debug/lib \ - -D Boost_USE_STATIC_LIBS=ON \ - ... -``` - -#### x64 - -``` -$ pwd -/cygdrive/d/workspace/build/test_project/mingw/x64/debug - -$ cmake -G "Unix Makefiles" \ - -D CMAKE_BUILD_TYPE=Debug \ - -D CMAKE_C_COMPILER=x86_64-w64-mingw32-gcc \ - -D CMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++ \ - -D BOOST_ROOT=/cygdrive/d/workspace/third-party/boost_1_61_0/mingw \ - -D BOOST_LIBRARYDIR=/cygdrive/d/workspace/third-party/boost_1_61_0/mingw/stage/x64/debug/lib \ - -D Boost_USE_STATIC_LIBS=ON \ - ... -``` 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' %} diff --git a/_posts/2018-02-18-peculiar-indentation.md b/_posts/2018-02-18-peculiar-indentation.md deleted file mode 100644 index 7832194..0000000 --- a/_posts/2018-02-18-peculiar-indentation.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: Peculiar Haskell indentation -excerpt: > - An explanation for nasty `parse error`s I used to get for nested `do` - blocks. -category: Haskell -custom_css: - - syntax.css ---- -I've fallen into a Haskell indentation pitfall. -I think it must be common, so I'm describing it here. - -The problem is that indentation rules in `do` blocks are not intuitive to me. -For example, the following function is valid Haskell syntax: - -```haskell -foo1 :: IO () -foo1 = - alloca $ \a -> - alloca $ \b -> - alloca $ \c -> do - poke a (1 :: Int) - poke b (1 :: Int) - poke c (1 :: Int) - return () -``` - -In fact, this funnier version is also OK: - -```haskell -foo2 :: IO () -foo2 = alloca $ \a -> - alloca $ \b -> - alloca $ \c -> do - poke a (1 :: Int) - poke b (1 :: Int) - poke c (1 :: Int) - return () -``` - -If you add an outer `do` however, things become a little more complicated. -For example, this is the valid version of the functions above with an outer -`do`: - -```haskell -foo3 :: IO () -foo3 = do - alloca $ \a -> - alloca $ \b -> - alloca $ \c -> do - poke a (1 :: Int) - poke b (1 :: Int) - poke c (1 :: Int) - return () -``` - -Notice the extra indentation for each of the `alloca`s. -When I tried to remove these seemingly excessive indents, GHC complained with -the usual `parse error (possibly incorrect indentation or mismatched -brackets)`. - -```haskell -foo4 :: IO () -foo4 = do - alloca $ \a -> - alloca $ \b -> - alloca $ \c -> do - poke a (1 :: Int) - poke b (1 :: Int) - poke c (1 :: Int) - return () -``` - -The truth is, the rules for desugaring `do` blocks are surprisingly simple and -literal. -GHC inserts semicolons according to the rules [found in the Wikibook]. -So it inserts semicolons between the `alloca`s on the same level, so `foo4` -becomes: - -```haskell -foo4 :: IO () -foo4 = do - { alloca $ \a -> - ; alloca $ \b -> - ; alloca $ \c -> do - { poke a (1 :: Int) - ; poke b (1 :: Int) - ; poke c (1 :: Int) - ; return () - } - } -``` - -[found in the Wikibook]: https://en.wikibooks.org/wiki/Haskell/Indentation#Explicit_characters_in_place_of_indentation - -The semicolons after `->` are clearly invalid Haskell syntax, hence the error. - -P.S. To compile the functions above, you need to include them in a module and -add proper imports, e.g. - -```haskell -module PeculiarIndentation where - -import Foreign.Marshal.Alloc (alloca) -import Foreign.Storable (poke) -``` diff --git a/_posts/2019-09-30-recurring-decimals.md b/_posts/2019-09-30-recurring-decimals.md deleted file mode 100644 index 741d083..0000000 --- a/_posts/2019-09-30-recurring-decimals.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: Recurring decimals -excerpt: > - Eighth-grader thoughts on recurring decimals. -category: Math -mathjax: true ---- -{% include common/mathjax_workaround.md %} - -First, let's determine that - -$$ -\newcommand\naturals{\mathbb{N}} -\newcommand\rationals{\mathbb{Q}} -\newcommand\reals{\mathbb{R}} - -\newcommand\xs{x_{1}x_{2}\dots x_n} -\newcommand\nines{\overbrace{99\dots 9}^n} -\newcommand\pq{\frac{p}{q}} -\newcommand\qp{\frac{q}{p}} - -0.(9) = 1 -$$ - -This may seem counter-intuitive, but demonstrably true. -If $$0.(9) \neq 1$$, then $$\exists n \in \reals: 0.(9) < n < 1$$. -To put it another way, there must be a number greater than 0.(9) and lesser -than 1, equal to neither. -Thinking about it makes it obvious this is not true. - -Slightly more formally, - -$$ -\begin{align*} -1 - 0.9 &= \frac{1}{10} \\ -1 - 0.99 &= \frac{1}{100} \\ -1 - 0.999 &= \frac{1}{10^{-3}} \\ -\dots \\ -1 - 0.\nines &= \frac{1}{10^n} \\ -\end{align*} -$$ - -If $$0.(9) \neq 1$$, the following must hold: - -$$ -\forall n \in \naturals, \exists x \in \reals: x < \frac{1}{10^n} -$$ - -It's clear that the only such number is 0, making 0.(9) and 1 equal. - -Let $$n \in [1,9]$$. -Is there $$\pq \in \rationals: \pq = 0.(n)$$? - -For $$n = 9$$, we've established $$p = 1, q = 1$$. -For the other values of $$n$$ we can observe that - -$$ -\begin{align*} -0.(1) \times 9 &= 0.(9) = 1 \\ -0.(2) \times 9/2 &= 0.(9) = 1 \\ -0.(3) \times 9/3 &= 0.(9) \\ -\dots \\ -0.(8) \times 9/8 &= 0.(9) \\ -0.(9) \times 1 &= 0.(9) -\end{align*} -$$ - -So, - -$$ -\forall n \in [1,9], \frac{n}{9} = 0.(n) -$$ - -In general, let's demonstrate that - -$$ -\forall n \in \naturals, n > 0, \forall 0.(x_{1}x_{2}\dots x_n), \exists \pq \in \rationals: \pq = 0.(\xs) -$$ - -Let $$p = \xs, q =\,\nines$$. -It's clear that - -$$ -\begin{align*} -0.(\xs) \times \qp &= 0.(\xs) \times \frac{\nines}{\xs} \\ -&= \left(\frac{\xs}{10^n} + \frac{\xs}{10^{2n}} + \dots\right) \times \frac{\nines}{\xs} \\ -&= \left(\frac{1}{10^n} + \frac{1}{10^{2n}} + \dots\right) \times\,\nines \\ -&= 0.(9) \\ -&= 1 -\end{align*} -$$ - -Finally, $$0.(\xs) \times \qp = 1 \implies \pq = 0.(\xs)$$. diff --git a/_posts/2020-02-24-ssh-tunnel-windows.md b/_posts/2020-02-24-ssh-tunnel-windows.md deleted file mode 100644 index a847ff4..0000000 --- a/_posts/2020-02-24-ssh-tunnel-windows.md +++ /dev/null @@ -1,154 +0,0 @@ ---- -title: Persistent SSH tunnel -excerpt: ... using Cygwin. ---- -SSH tunneling is awesome. -For some reason, I've only recently learned about this feature, but I've been -immediately blown away by how useful it can be. - -Basically, to use SSH tunneling (a.k.a. port forwarding) you need to have a SSH -client (`ssh`) with an access to a SSH server. -You can then access any port on any host your SSH server has access to. -It works like this: - -* your SSH client establishes a connection to the SSH server, -* the client asks the server to forward incoming requests to the destination -host, -* the client listens to the proxy port on the local machine, and forwards -requests to the SSH server. - -Say, you have access to SSH server `gateway` on port 22, and you want to gain -access to HTTPS server `dest` on port 443, which is only accessible from the -network both it and the SSH server belong to. -You can then run something like - -``` -ssh -L 4433:dest:443 gateway -p 22 -``` - -And now you can access `dest` at `https://localhost:4433/`. -That's brilliant, really. - -But there's more. -You can make a _reverse_ tunnel, allowing you to give access to any host your -client computer has access to, via a remote SSH server. -It works like this: - -* your SSH client establishes a connection with the SSH server, -* the client asks the server to listen to a port of your choosing and forward -incoming requests to the client, -* the client forwards incoming requests to the destination host. - -This, as I've recently learned, is a common pattern to subvert corporate -firewalls, which frequently forbid incoming connections. -Say, you want to access your work computer from home via RDP. -Both your home and your work computers have access to a SSH server `gateway` on -port 22 (you might want to change it to port 80 or 443 if your outside -connections are filtered). - -You can then run something like (notice the `-R`) - -``` -ssh -R 13389:127.0.0.1:3389 gateway -p 22 -``` - -and now you can connect to `gateway:13389` from your home computer using a RDP -client. -Even more brilliant! - -You might need to set the `GatewayPorts` setting to `yes` or `clientspecified` -on your SSH server (typically in "/etc/ssh/sshd_config"). - -Batch mode ----------- - -If you want to establish a reverse SSH tunnel automatically, some tweaking is -required. -First, set some SSH client options: - -* `-F /dev/null` to disregard the user config, -* `-oBatchMode=yes` to run non-interactively, -* `-oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null` to disable server -verification (optional), -* `-oExitOnForwardFailure=yes` to exit if port forwarding fails, -* `-oServerAliveCountMax=3 -oServerAliveInterval=15` to break the connection if -the server or the network is down, -* `-N -n -T` to only forward the ports and not execute the shell or any -additional commands. - -Thus, the full command would be something like - -``` -ssh \ - -F /dev/null \ - -oBatchMode=yes \ - -oStrictHostKeyChecking=no \ - -oUserKnownHostsFile=/dev/null \ - -oExitOnForwardFailure=yes \ - -oServerAliveCountMax=3 \ - -oServerAliveInterval=15 \ - -N -n -T \ - -R 13389:127.0.0.1:3389 \ - user@gateway -p 22 \ - -i ~/.ssh/tunnel -``` - -Adjust the `user@gateway -p 22` part accordingly. - -Notice also `-i ~/.ssh/tunnel`. -It's the path to the SSH key used to authenticate with the server. -It can't have a passphrase, since the command will be run non-interactively, -and the public key must be in the server's authorized_keys file. - -For best results, you should also adjust some settings on the SSH server. -Namely, you should enable client keep-alives on the server using something like - -``` -ClientAliveCountMax 3 -ClientAliveInterval 15 -``` - -Unless you do that, even if the client breaks the connection, you won't be able -to re-establish it for a long-ish time, since the server wouldn't know that the -original connection is no longer valid. - -As a service ------------- - -Cygwin is awesome. -I've been using for 10+ years, and it has never failed me. -It comes with a SSH server, a client (you need to install the `openssh` package -for both of these), and a service manager, `cygrunsrv`. -`cygrunsrv` is similar to [NSSM], as it allows to wrap any executable into a -native Windows service. - -[NSSM]: https://nssm.cc/ - -Using `cygrunsrv`, you can create a Windows service to establish a reverse SSH -tunnel automatically. - -``` -cygrunsrv \ - -I ssh_tunnel \ - -p /usr/bin/ssh \ - --args '-F /dev/null -oBatchMode=yes -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oExitOnForwardFailure=yes -oServerAliveCountMax=3 -oServerAliveInterval=15 -N -n -T -R 13389:127.0.0.1:3389 user@gateway -p 22 -i ~/.ssh/tunnel' \ - --disp 'Reverse SSH tunnels' \ - --user user \ - --neverexits \ - --preshutdown -``` - -Adjust the `--user` and the `--args` values accordingly. - -You can then run `services.msc` and adjust the recovery settings for the -service to restart if `ssh` fails: - -
-
- - services.msc - -
-
- -And voilĂ , you have an automatic reverse SSH tunnel on Windows for you! diff --git a/_posts/2020-05-06-docker-bind-mounts.md b/_posts/2020-05-06-docker-bind-mounts.md deleted file mode 100644 index 9853331..0000000 --- a/_posts/2020-05-06-docker-bind-mounts.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -title: 'Docker: bind mounts & file ownership' -excerpt: Docker + bind mounts + non-root users = pain. ---- -If you want to: - -1. run your Docker service as a user other than root, -2. share a writable directory between your host and the container, - -you're in for a treat! -The thing is, files stored in the shared directory retain their ownership (and -by that I mean their UIDs and GIDs, as they're the only thing that matters) -after being mounted in the container. - -Case in point: - - docker run -it --rm -v "$( pwd ):/data" alpine touch /data/test.txt - -would create file ./test.txt owned by root:root. - -You can fix that by using the `--user` parameter: - - docker run -it --rm -v "$( pwd ):/data" --user "$( id -u ):$( id -g )" alpine touch /data/test.txt - -That would create file ./test.txt owned by the current user (if the current -working directory is writable by the current user, of course). - -More often though, instead of a simple `touch` call, you have a 24/7 service, -which absolutely mustn't run as root, regardless of whether `--user` was -specified or not. -In such cases, the logical solution would be to create a regular user in the -container, and use it to run the service. -In fact, that's what many popular images do, i.e. [Redis][Redis Dockerfile] and -[MongoDB][MongoDB Dockerfile]. - -[Redis Dockerfile]: https://github.com/docker-library/redis/blob/cc1b618d51eb5f6bf6e3a03c7842317b38dbd7f9/6.0/Dockerfile#L4 -[MongoDB Dockerfile]: https://github.com/docker-library/mongo/blob/5cbf7be9a486932b7e472a39e432c9a444628465/4.2/Dockerfile#L4 - -How do you run the service as regular user though? -It's tempting to use the `USER` directive in the Dockerfile, but that can be -overridden by `--user`: - - $ cat Dockerfile - FROM alpine - - RUN addgroup --gid 9099 test-group && \ - adduser \ - --disabled-password \ - --gecos '' \ - --home /home/test-user \ - --ingroup test-group \ - --uid 9099 \ - test-user - - RUN touch /root.txt - USER test-user:test-group - RUN touch /home/test-user/test-user.txt - - CMD id && stat -c '%U %G' /root.txt && stat -c '%U %G' /home/test-user/test-user.txt - - $ docker build -t id . - ... - - $ docker run -it --rm id - uid=9099(test-user) gid=9099(test-group) - root root - test-user test-group - - $ docker run -it --rm --user root id - uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video) - root root - test-user test-group - -I suppose that's the reason why many popular images override ENTRYPOINT, using -a custom script (and `gosu`, which is basically `sudo`, I think) to forcefully -drop privileges (for example, see [Redis][Redis entrypoint], -[MongoDB][MongoDB entrypoint]). - -[Redis entrypoint]: https://github.com/docker-library/redis/blob/cc1b618d51eb5f6bf6e3a03c7842317b38dbd7f9/6.0/docker-entrypoint.sh#L11 -[MongoDB entrypoint]: https://github.com/docker-library/mongo/blob/5cbf7be9a486932b7e472a39e432c9a444628465/4.2/docker-entrypoint.sh#L12 - -Now, what if such service needs persistent storage? -A good solution would be to use Docker volumes. -For development though, you often need to just share a directory between your -host and the container, and it has to be writable by both the host and the -container process. -This can be accomplished using _bind mounts_. -For example, let's try to map ./data to /data inside a Redis container (this -assumes ./data doesn't exist and you're running as regular user with UID 1000; -press Ctrl+C to stop Redis): - - $ mkdir data - - $ stat -c '%u' data - 1000 - - $ docker run -it --rm --name redis -v "$( pwd )/data:/data" redis:6.0 - ... - - $ stat -c '%u' data - 999 - -As you can see, ./data changed its owner from user with UID 1000 (the host -user) to user with UID 999 (the `redis` user inside the container). -This is done in Redis' ENTRYPOINT script, just before dropping root privileges -so that the `redis-server` process owns the /data directory and thus can write -to it. - -If you want to preserve ./data ownership, Redis' image (and many others) -explicitly accomodates for it by _not_ changing its owner if the container is -run as anybody other than root. -For example: - - $ mkdir data - - $ stat -c '%u' data - 1000 - - $ docker run -it --rm --name redis -v "$( pwd )/data:/data" --user "$( id -u ):$( id -g )" redis:6.0 - ... - - $ stat -c '%u' data - 1000 - -Sometimes `--user` is not enough though. -That specified user is almost certainly missing from container's /etc/passwd, -it doesn't have a $HOME, etc. -All of that could cause problems with some applications. - -One scenario I had to deal with is making an image that bundles all the gems -(and a specific Ruby version) for my Ruby web application. -That application shouldn't be run as root, but it must be able to pick up code -changes on the fly, and I should be able `docker exec` into the container, -update the dependencies (along with Gemfile[.lock], and those changes should be -reflected on the host without messing up file metadata), and restart the app. -It's quite easy to install the dependencies in the Dockerfile, but they (along -with the mapped Gemfile[.lock]) should be writable by the user running the -service. -The solution often suggested is to create a container user with a fixed UID -(that would match the host user UID). -That way, it would be able to update the dependencies stored in the container, -as well as write to the bind mount owned by the host user with the same UID. -Additionally, file ownership info would be preserved on the host! - -We can create a user with a fixed UID when - -1. building the image (using build `ARG`uments), -2. first starting the container by passing the required UID using environment -variables. - -The advantages of creating the user when building the image is that we can also -install the dependencies in the Dockerfile, thus eliminating the need to -rebuild them for every other application. -The disadvantage is that the image would need to be rebuilt for every user on -every machine. - -Creating the user when first starting the container has the advantage of not -requiring image rebuilds. -But, as the dependencies need to be installed after creating the user, you'd -have to waste resources by installing them for every user and every app on -every machine (each time when creating a container). - -For my project [jekyll-docker] I opted for the former approach, making sure the -`jekyll` process runs with the same UID as the user who built the image (unless -it was built by root, in which case it falls back to a custom UID of 999). - -[jekyll-docker]: https://github.com/egor-tensin/jekyll-docker - -Useful links ------------- - -* [Docker and \-\-userns-remap, how to manage volume permissions to share data between host and container?](https://stackoverflow.com/q/35291520/514684) -* [What is the (best) way to manage permissions for Docker shared volumes?](https://stackoverflow.com/q/23544282/514684) -* [Handling Permissions with Docker Volumes](https://denibertovic.com/posts/handling-permissions-with-docker-volumes/) -* [File Permissions: the painful side of Docker](https://blog.gougousis.net/file-permissions-the-painful-side-of-docker/) -* [Avoiding Permission Issues With Docker-Created Files](https://vsupalov.com/docker-shared-permissions/) diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/shared.hpp deleted file mode 100644 index 796ea85..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/shared.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -inline int shared() { - static int n = 0; - return ++n; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.cpp deleted file mode 100644 index 330ba80..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "another.hpp" - -#include - -inline void shared() { - std::cout << "another.cpp: shared()\n"; -} - -void another() { - shared(); -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.hpp deleted file mode 100644 index 9c26d3f..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void another(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/main.cpp deleted file mode 100644 index e278b9f..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/main.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "another.hpp" - -#include - -inline void shared() { - std::cout << "main.cpp: shared()\n"; -} - -int main() { - shared(); - another(); - return 0; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.cpp deleted file mode 100644 index f13b3a1..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "another.hpp" -#include "shared.hpp" - -void another() { - Test test; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.hpp deleted file mode 100644 index 9c26d3f..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void another(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/main.cpp deleted file mode 100644 index b3118c1..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "another.hpp" -#include "shared.hpp" - -int main() { - Test test; - another(); - return 0; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/shared.hpp deleted file mode 100644 index ef4da34..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/shared.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -struct Test { - Test(); -}; - -inline Test::Test() { - static int x = 0; - std::cout << ++x << '\n'; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/main.cpp deleted file mode 100644 index fde1a43..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "proxy.hpp" -#include "shared.hpp" - -#include - -int main() { - std::cout << shared() << '\n'; - std::cout << proxy() << '\n'; - return 0; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.cpp deleted file mode 100644 index 78e4611..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "proxy.hpp" -#include "shared.hpp" - -int proxy() { - return shared(); -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.hpp deleted file mode 100644 index 7dfc52a..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -int proxy(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/shared.hpp deleted file mode 100644 index 647f49e..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/shared.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -static int shared() { - static int n = 0; - return ++n; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/main.cpp deleted file mode 100644 index fde1a43..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "proxy.hpp" -#include "shared.hpp" - -#include - -int main() { - std::cout << shared() << '\n'; - std::cout << proxy() << '\n'; - return 0; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.cpp deleted file mode 100644 index 78e4611..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "proxy.hpp" -#include "shared.hpp" - -int proxy() { - return shared(); -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.hpp deleted file mode 100644 index 7dfc52a..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -int proxy(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/shared.hpp deleted file mode 100644 index 28de441..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/shared.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -static inline int shared() { - static int x = 0; - return ++x; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/main.cpp deleted file mode 100644 index fde1a43..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "proxy.hpp" -#include "shared.hpp" - -#include - -int main() { - std::cout << shared() << '\n'; - std::cout << proxy() << '\n'; - return 0; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.cpp deleted file mode 100644 index 78e4611..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "proxy.hpp" -#include "shared.hpp" - -int proxy() { - return shared(); -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.hpp deleted file mode 100644 index 7dfc52a..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -int proxy(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/shared.hpp deleted file mode 100644 index e21a00c..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/shared.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -namespace { - -inline int shared() { - static int x = 0; - return ++x; -} - -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.cpp deleted file mode 100644 index cc7556d..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "another.hpp" - -#include - -namespace { - -struct Test { - Test() { - std::cout << "another.cpp: Test::Test()\n"; - } - - float y = 1.; -}; - -} - -void another() { - Test test; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.hpp deleted file mode 100644 index 9c26d3f..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void another(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/main.cpp deleted file mode 100644 index e383ded..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/main.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "another.hpp" - -#include - -namespace { - -struct Test { - Test() { - std::cout << "main.cpp: Test::Test()\n"; - } - - int x = 1; -}; - -} - -int main() { - Test test; - std::cout << test.x << '\n'; - another(); - return 0; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.cpp deleted file mode 100644 index 0e0bff9..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "another.hpp" - -#include - -struct Test { - Test() { - std::cout << "another.cpp: Test::Test()\n"; - } - - float y = 1.; -}; - -void another() { - Test test; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.hpp deleted file mode 100644 index 9c26d3f..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void another(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/main.cpp deleted file mode 100644 index abd42b7..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/main.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "another.hpp" - -#include - -struct Test { - Test() { - std::cout << "main.cpp: Test::Test()\n"; - } - - int x = 1; -}; - -int main() { - Test test; - std::cout << test.x << '\n'; - another(); - return 0; -} -- cgit v1.2.3