Let's recap that. I wanted to control the order of constructors mostly to control the order of destructors (which should be inverse).
Then a non-GlobalPtr/-InitInstance object allocating memory would not cause a crash if the memory manager is destroyed before it. It looks like there is another way to make that. std::atexit (https://en.cppreference.com/w/cpp/utility/program/atexit) docs says: "The functions will be called during the destruction of the static objects, in reverse order: if A was registered before B, then the call to B is made before the call to A. Same applies to the ordering between static object constructors and the calls to atexit: see std::exit <https://en.cppreference.com/w/cpp/utility/program/exit>" And std::exit (https://en.cppreference.com/w/cpp/utility/program/exit) says: "1) destructors of objects with static storage duration are called in reverse order of completion of their constructors or the completion of their dynamic initialization <https://en.cppreference.com/w/cpp/language/initialization#Dynamic_initialization>, and the functions passed to std::atexit <https://en.cppreference.com/w/cpp/utility/program/atexit> are called in reverse order they are registered (last one first). a) any static objects whose initialization was completed before the call to std::atexit <https://en.cppreference.com/w/cpp/utility/program/atexit> for some function F will be destroyed after the call to F during program termination. b) any static objects whose construction began after the call to std::atexit <https://en.cppreference.com/w/cpp/utility/program/atexit> for some function F will be destroyed before the call to F during program termination (this includes the case where std::atexit <https://en.cppreference.com/w/cpp/utility/program/atexit> was called from the constructor of the static object)" So a static storage object allocating memory with the default pool will call the allocator before it's constructor begins (and of course, completes) so if the allocator registers a atexit handler for cleanup, that handler will be called after the object destructor. I did a test and result in Linux (clang and gcc), Windows (VS 2017 and 2019) and MacOS (clang) is identical: // a.cpp #include <cstdio> extern void fb(); struct CA { CA(int n) : n(n) { printf("CA(%d)\n", n); if (n == 2) fb(); } ~CA() { printf("~CA(%d)\n", n); } int n; }; static CA ca1(1); static CA ca2(2); static CA ca3(3); int main() { printf("main\n"); return 0; }; ---- // b.cpp #include <cstdio> #include <cstdlib> struct CB { CB(int n) : n(n) { printf("CB(%d)\n", n); } ~CB() { printf("~CB(%d)\n", n); } void f() { printf("CB::f(%d)\n", n); } int n; }; static CB cb1(1); static CB cb2(2); static void fexit() { printf("fexit\n"); } void fb() { printf("fb\n"); atexit(fexit); } --- result: CA(1) CA(2) fb CA(3) CB(1) CB(2) main ~CB(2) ~CB(1) ~CA(3) ~CA(2) fexit ~CA(1) Adriano On Wed, Apr 14, 2021 at 2:25 PM Adriano dos Santos Fernandes < adrian...@gmail.com> wrote: > Hi! > > C++ guarantees the execution order of constructors only inside the same > translation unit (say, a .cpp file) for global objects. > > It also guarantees inverse order of destructors in relation to > constructors order. > > But constructor order across translation units are undefined. > > We used to have problems with that. > > Then things like InitInstance and GlobalPtr were born. > > As I understand, in "common" (not Firebird code) C++, usage of > new/malloc on library code not paired with delete/free becomes memory > leaks when that library are unloaded. > > But in Firebird these goes to default pool with are deallocated at > library exit. > > It's good thing, but it's were the problem starts. > > I was doing some tests integrating Boost.Test library in Firebird code. > And then it segfaults at exit. > > It uses global std objects which in this case have theirs destructors > called after Firebird default pool are already cleaned up. > > In current code, we have re2 C++ library statically linked. > > It looks like it works because it does not have global objects, i.e., we > rely on re2 implementation details. > > I was looking at better way to solve this problem. > > GCC/clang has init_priority attribute: > https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html > > It's not well documented. Here we see some implementation details about > default value: > https://gcc.gnu.org/legacy-ml/gcc-help/2015-08/msg00027.html > > I have tested with common/classes/init.cpp and this solved the specific > problem I had with Boost.Test: > > Cleanup global __attribute__ ((init_priority (2000))); > > For MSVC I didn't tested, but found this docs with probably could be > used for similar behavior: > > > https://docs.microsoft.com/en-us/cpp/preprocessor/init-seg?redirectedfrom=MSDN&view=msvc-160 > > > Adriano >
Firebird-Devel mailing list, web interface at https://lists.sourceforge.net/lists/listinfo/firebird-devel