{"id":13729673,"url":"https://github.com/graphitemaster/0xABAD1DEA","last_synced_at":"2025-05-08T02:30:33.226Z","repository":{"id":142016429,"uuid":"64472058","full_name":"graphitemaster/0xABAD1DEA","owner":"graphitemaster","description":"Static global objects with constructors and destructors made useful in C++","archived":false,"fork":false,"pushed_at":"2016-07-29T11:01:08.000Z","size":13,"stargazers_count":27,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-14T20:38:15.158Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/graphitemaster.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-07-29T10:19:52.000Z","updated_at":"2024-04-15T11:19:38.000Z","dependencies_parsed_at":"2023-07-07T07:32:34.329Z","dependency_job_id":null,"html_url":"https://github.com/graphitemaster/0xABAD1DEA","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphitemaster%2F0xABAD1DEA","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphitemaster%2F0xABAD1DEA/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphitemaster%2F0xABAD1DEA/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphitemaster%2F0xABAD1DEA/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/graphitemaster","download_url":"https://codeload.github.com/graphitemaster/0xABAD1DEA/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252986544,"owners_count":21836176,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T02:01:03.689Z","updated_at":"2025-05-08T02:30:33.009Z","avatar_url":"https://github.com/graphitemaster.png","language":"C++","funding_links":[],"categories":["C++"],"sub_categories":[],"readme":"# 0xABAD1DEA\n\nThis little header provides an alternative way to construct and destruct static\nglobal objects.\n\n# How to use\nAdd `0xabad1dea.cpp` and `0xabad1dea.h` to your project.\n\n# Examples\n\n## Trivial\n```c++\nstruct A {\n  A() { printf(\"A::A()\\n\"); }\n  ~A() { printf(\"A::~A()\\n\"); }\n};\nStaticGlobal\u003cA\u003e gMyA0(\"MyA0\"), gMyA1(\"MyA1\"); // uninitialized\n\nint main() {\n  StaticGlobals::initialize(); // calls the constructors objects are now initialized\n\n  // typically best to use atexit(StaticGlobals::deinitialize)\n  StaticGlobals::deinitialize(); // calls the destructors\n}\n```\n\n## Calling individuals\n```c++\nint main() {\n  StaticNode *node = StaticGlobals::find(\"MyA1\");\n  if (node) node-\u003econstruct(); // manually initialize MyA1\n  // ...\n  if (node) node-\u003edestruct(); // manually destruct MyA1\n}\n```\n\n## Removing individuals\n```c++\nint main() {\n StaticNode *node = StaticGlobals::find(\"MyA1\");\n if (node) StaticGlobals::remove(node); // remove MyA1 from initialization and destruction\n}\n```\n\n## Real world example\nHave a memory allocator which needs to be allocated before all other static globals,\nyou could lazily construct it with a singleton pattern or you could use something like:\n```c++\nStaticGlobal\u003cAllocator\u003e gAllocator(\"Allocator\");\n/// ...\nint main() {\n  atexit(StaticGlobals::deinitialize); // be sure to call destructors of statics at exit\n  StaticNode *node = StaticGlobals::find(\"Allocator\");\n  if (node) {\n    node-\u003einitialize(); // call the constructor\n    StaticGlobals::remove(node); // remove from the statics list\n  }\n  StaticGlobals::initialize(); // initialize all other statics\n\n  // ... typical code\n\n  if (node)\n    node-\u003edeinitialize(); // deinitialize the allocator\n}\n```\n\nOf course the other statics may depend on the allocator to exist (e.g free memory)\nso we cannot deinitialize in main, what we could do is something like this which\nuses atexit to register a lambda function which destroys the statics before the\nother atexit handler for all other static global objects runs.\n```c++\nStaticNode *node;\nint main() {\n  node = StaticGlobals::find(\"Allocator\");\n  if (node) {\n    node-\u003einitialize(); // call the constructor\n    atexit([](){ node-\u003edeinitialize(); }); // this atexit will be called first\n    StaticGlobals::remove(node); // remove from the statics list\n  }\n  StaticGlobals::initialize(); // initialize all other statics\n  atexit(StaticGlobals::deinitialize); // be sure to call destructors of statics at exit\n\n  // normal code\n}\n```\n\n# How it works\nUsing an intrusive linked list to thread a doubly linked list of each global\nusing static storage and then iterating that linked list to actually call\nplacement new on uninitialized storage to construct the static objects.\nThe same is done for destruction except the tail end of the linked list is\nused so things get destroyed in reverse order as they were constructed.\n\nThe intrusive use of the node makes it convienent to do type-erasure, avoid heap\nallocations and most importantly get the associated data backing the actual\nobject. Take a look at the definition of `StaticGlobal`. It uses a technique to\ncarry over the template type into node's constructor which the node then uses\nto get the address of two wrapper functions for constructing and destructing\nthe object. The layout of `StaticGlobal` is such that immediately after the\nnode object there is the data we'll be using to construct the object. So\nby going one past a `StaticNode` pointer we're effectively in the data for that\nnode.\n\n# Thread safety\nSince this system does depend on existing C++ static constructors to function\nand C++ permits an implementation to thread the initialization of static objects\na global lock is used on the linked list. The lock is implemented in terms of\n`pthread_mutex_t` but can be replaced with a more suitable mutex or locking\nprimitive of your choosing (it's only ~8 lines or so in the source file.)\n\n# License\n```\nThis is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, compile, sell, or\ndistribute this software, either in source code form or as a compiled\nbinary, for any purpose, commercial or non-commercial, and by any\nmeans.\n\nIn jurisdictions that recognize copyright laws, the author or authors\nof this software dedicate any and all copyright interest in the\nsoftware to the public domain. We make this dedication for the benefit\nof the public at large and to the detriment of our heirs and\nsuccessors. We intend this dedication to be an overt act of\nrelinquishment in perpetuity of all present and future rights to this\nsoftware under copyright law.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\nFor more information, please refer to \u003chttp://unlicense.org/\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphitemaster%2F0xABAD1DEA","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraphitemaster%2F0xABAD1DEA","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphitemaster%2F0xABAD1DEA/lists"}