{"id":18720479,"url":"https://github.com/stiffstream/noexcept-ctcheck","last_synced_at":"2025-11-10T21:30:15.908Z","repository":{"id":92244880,"uuid":"207224276","full_name":"Stiffstream/noexcept-ctcheck","owner":"Stiffstream","description":"A few C++ macros for checking noexcept-ness at the compile time","archived":false,"fork":false,"pushed_at":"2019-09-10T09:36:52.000Z","size":9,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-12-28T11:28:20.852Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Stiffstream.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-09T04:30:48.000Z","updated_at":"2021-01-17T17:11:13.000Z","dependencies_parsed_at":"2023-06-25T23:43:30.655Z","dependency_job_id":null,"html_url":"https://github.com/Stiffstream/noexcept-ctcheck","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stiffstream%2Fnoexcept-ctcheck","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stiffstream%2Fnoexcept-ctcheck/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stiffstream%2Fnoexcept-ctcheck/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stiffstream%2Fnoexcept-ctcheck/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Stiffstream","download_url":"https://codeload.github.com/Stiffstream/noexcept-ctcheck/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239583688,"owners_count":19663247,"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-11-07T13:31:15.872Z","updated_at":"2025-11-10T21:30:15.871Z","avatar_url":"https://github.com/Stiffstream.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# What is noexcept-compile-time-check?\n\nThe noexcept-compile-time-check (or noexcept-ctcheck for short) is a C++11 library with several simple macros that give you some control over the content of `noexcept` methods and functions in modern C++.\n\nA simple example just to give you some impression:\n\n```cpp\n#include \u003cnoexcept_ctcheck/pub.hpp\u003e\n...\nclass some_complex_container {\n   one_container first_data_part_;\n   another_container second_data_part_;\n   ...\npublic:\n   friend void swap(some_complex_container \u0026 a, some_complex_container \u0026 b) noexcept {\n      using std::swap;\n      // We'll get a compile-time error if that swap is not noexcept.\n      NOEXCEPT_CTCHECK_ENSURE_NOEXCEPT_STATEMENT(\n         swap(a.first_data_part_, b.first_data_part_));\n      NOEXCEPT_CTCHECK_ENSURE_NOEXCEPT_STATEMENT(\n         swap(a.second_data_part_, b.second_data_part_));\n      ...\n   }\n   ...\n   void clean() noexcept {\n      // We'll get a compile-time error if clean() for subcontainers is not noexcept.\n      NOEXCEPT_CTCHECK_ENSURE_NOEXCEPT_STATEMENT(first_data_part_.clean());\n      NOEXCEPT_CTCHECK_ENSURE_NOEXCEPT_STATEMENT(second_data_part_.clean());\n      ...\n   }\n   ...\n};\n\nclass some_resource_holder {\npublic:\n   ...\n   // Note that release() is not noexcept method and can throw.\n   void release() { ... }\n\n   // The destructor of some_resource_holder should be noexcept.\n   ~some_resource_holder() noexcept {\n      try {\n         // We'll get a compile-time error if release() is noexcept and out try-catch is redundant.\n         NOEXCEPT_CTCHECK_ENSURE_NOT_NOEXCEPT_STATEMENT(release());\n      } catch(...) {}\n   }\n};\n```\n\n# The motivation\n\nThere are some places where we rely on the absence of exceptions in some code: implementation of swap-functions, move- and/or copy-operators, destructors, cleanup functions and so on. It is safe to call only non-throwing methods/functions in those places. The modern C++ (C++11 and above) has `noexcept` modificator for methods/functions. That modificator significantly simplifies the writing of exception safe code. We can check the signatures of called functions and do appropriate actions. For example:\n\n```cpp\nclass some_complex_business_logic_class {\n   first_resource_type first_resource_; // Has noexcept release() method.\n   second_resource_type second_resource_; // Has close() method that throws.\n   ...\npublic:\n   ~some_complex_business_logic_class() noexcept {\n      // It's safe to call release() for the first resource without enclosing try-catch.\n      first_resource_.release();\n\n      // But the call to second resource's close() should be enclosed in try-catch.\n      try { second_resource_.close(); } catch(...) {}\n   }\n   ...\n};\n```\nBut there is a problem: the compiler doesn't warn if I call some throwing method/function inside my noexcept-method/function. It opens a wide field for subtle errors.\n\nFor example, suppose that I make a mistake and mixed up the info about `release()` and `close()` exception safety. In reality `first_resource_type::release()` throws, but `second_resource_type::close()` doesn't. It means that my implementation of `some_complex_business_logic_class`'s destructor is wrong. But the compiler doesn't tell me about that.\n\nOr another case: suppose that I used some 3-rd party library v.1.0 in that `first_resource_type::release()` is `noexcept`. I wrote some code that relied on the fact that `release()` didn't throw exceptions. But after some time I switch to v.3.0 of that library. And in v.3.0 `release()` isn't `noexcept` anymore. I should rewrite a part of my code, but I can forget about that and compiler doesn't help me here.\n\nThe noexcept-ctcheck library contains several simple macros that allow forcing noexcept-ness of some code fragments in the compile-time. It allows getting some help from a compiler and that especially important for the maintenance of old code.\n\n## Origins\n\nThe first version of those macros was developed during the evolution of [RESTinio](https://github.com/Stiffstream/restinio) library. It helped us to catch some errors with the exception safety of callbacks passed to Asio. So the idea behind noexcept-ctcheck library has already proved its evaluability.\n\n## Why macros?\n\nThe similar effect can be obtained by using raw `static_assert` in the code. For example, we can write:\n```cpp\nstatic_assert(noexcept(close()), \"close() is expected to be noexcept\");\nclose();\n```\ninstead of:\n```cpp\nNOEXCEPT_CTCHECK_ENSURE_NOEXCEPT_STATEMENT(close());\n```\nBut macros has an important advantage: they can easily be turned off. It can be necessary, for example, if you update some 3-rd party library and get too many compile-time errors.\n\n# What is inside?\n\nThere is just one header-file that should be included: `noexcept_ctcheck/pub.hpp`. It contains several macros with names like `NOEXCEPT_CTCHECK_`.\n\n## The main working principle\n\nThe macros are divided into two groups.\n\nThe macros from the first group performs compile-time checks and then execute the specified statement. Those macros are in the following form:\n\n```cpp\n#define NOEXCEPT_CTCHECK_ENSURE_NOEXCEPT_STATEMENT(stmt) \\\n\tdo { \\\n\t\tstatic_assert(noexcept(stmt), \"this statement is expected to be noexcept: \" #stmt); \\\n\t\tstmt; \\\n\t} while(false)\n```\nIt means that those macros can't be used as expressions. So we can write that:\n```cpp\nNOEXCEPT_CTCHECK_ENSURE_NOEXCEPT_STATEMENT(fclose(file));\n```\nBut can't write that:\n```cpp\nFILE * file = NOEXCEPT_CTCHECK_ENSURE_NOEXCEPT_STATEMENT(fopen(...));\n```\n\nThe macros from the second group only perform compile-time checking without execution of any code in the run-time. For example:\n```cpp\n// Only compile-time here.\nNOEXCEPT_CTCHECK_STATIC_ASSERT_NOEXCEPT(fopen(...));\nFILE * file = fopen(...);\n```\n\n## NOEXCEPT_CTCHECK_ENSURE_NOEXCEPT_STATEMENT\n\nThe macro `NOEXCEPT_CTCHECK_ENSURE_NOEXCEPT_STATEMENT(stmt)` performs a compile-time check and inserts the `stmt` into the source code (so `stmt` will be executed at run-time). It generates compile-time error if `stmt` is not noexcept.\n\nIt is intended to be used for the check that there is no need for enclosing try-catch blocks:\n```cpp\nclass some_resource_owner {\n   some_resource resource_;\n   ...\npublic:\n   ~some_resource_owner() noexcept {\n      NOEXCEPT_CTCHECK_ENSURE_NOEXCEPT_STATEMENT(release(resource_));\n      ...\n   }\n   ...\n};\n```\n\n## NOEXCEPT_CTCHECK_ENSURE_NOT_NOEXCEPT_STATEMENT\n\nThe macro `NOEXCEPT_CTCHECK_ENSURE_NOT_NOEXCEPT_STATEMENT(stmt)` performs a compile-time check inserts the `stmt` into the source code (so `stmt` will be executed at run-time). It generates compile-time error if `stmt` is noexcept.\n\nIt is intended to be used for the check that there is a need for enclosing try-catch blocks:\n```cpp\nclass some_resource_owner {\n   some_resource resource_;\n   ...\npublic:\n   ~some_resource_owner() noexcept {\n      try {\n         NOEXCEPT_CTCHECK_ENSURE_NOT_NOEXCEPT_STATEMENT(\n            release(resource_));\n      } catch(...) {}\n      ...\n   }\n   ...\n};\n```\n\n## NOEXCEPT_CTCHECK_STATIC_ASSERT_NOEXCEPT\n\nThe macro `NOEXCEPT_CTCHECK_STATIC_ASSERT_NOEXCEPT(stmt)` performs a compile-time check of `stmt` but doesn't inserts `stmt` into the code (so `stmt` will not be executed at run-time). It generates compile-time error if `stmt` is not noexcept.\n\nIt is intended to be used for the check that there is no need for enclosing try-catch blocks:\n```cpp\nvoid remove_appropriate_items_at_front(some_container_t \u0026 cnt) noexcept {\n\tNOEXCEPT_CTCHECK_STATIC_ASSERT_NOEXCEPT(cnt.empty());\n\tNOEXCEPT_CTCHECK_STATIC_ASSERT_NOEXCEPT(cnt.front());\n\tNOEXCEPT_CTCHECK_STATIC_ASSERT_NOEXCEPT(cnt.pop_front());\n\n\twhile(!cnt.empty() \u0026\u0026 some_conditions(cnt.front()) {\n\t\t// We don't expect exceptions here.\n\t\tcnt.pop_front();\n\t}\n}\n```\n\n## NOEXCEPT_CTCHECK_STATIC_ASSERT_NOT_NOEXCEPT\n\nThe macro `NOEXCEPT_CTCHECK_STATIC_ASSERT_NOT_NOEXCEPT(stmt)` performs a compile-time check of `stmt` but doesn't inserts `stmt` into the code (so `stmt` will not be executed at run-time). It generates compile-time error if `stmt` is noexcept.\n\nIt is intended to be used for the check that there is a need for enclosing try-catch blocks:\n```cpp\nvoid some_class::do_something() noexcept {\n\t// If the constructor of 'some_type' throws then we have to use try-catch block.\n\tNOEXCEPT_CTCHECK_STATIC_ASSERT_NOT_NOEXCEPT(\n\t\tsome_type{\n\t\t\t\tstd::declval\u003csome_param_type\u003e(),\n\t\t\t\tstd::declval\u003canother_param_type\u003e()});\n\ttry {\n \t\tsome_type resource{first_arg, second_arg};\n\t\t...\n\t} catch(...) {}\n\t...\n}\n```\n\n## How to disable compile-time checking?\n\nTo disable compile-time checking just define `NOEXCEPT_CTCHECK_DISABLE` symbol before including `noexcept_ctcheck/pub.hpp`. For example, that way:\n\n```cpp\n#define NOEXCEPT_CTCHECK_DISABLE\n#include \u003cnoexcept_ctcheck/pub.hpp\u003e\n```\n\n# How to get and use?\n\nIt is a header-only library without any external dependencies. Just copy `noexcept_ctcheck` directory into your project.\n\nA package for Conan and/or vcpkg can be created by a request. If you want noexcept-ctcheck be available via those package managers please open an issue.\n\n# License\n\nnoexcept-ctcheck is developed by [stiffstream](https://stiffstream.com) and distributed under BSD-3-Clause license.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstiffstream%2Fnoexcept-ctcheck","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstiffstream%2Fnoexcept-ctcheck","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstiffstream%2Fnoexcept-ctcheck/lists"}