Hmm, this issue tracker does not seem to have a feature to directly quote on the text so I'll try to emulate it.
"Unlike the encoders and decoders in
LOGCXX-112, the repo can't be effectively recovered after its destructed."
Agreed (I don't know log4cxx that well but to me it seems to be a complex structure so it makes sense).
"The repo will need to be destructed at some point unless you want to leak a lot of resources and then others would complain."
Of course, we need to make sure it is destructed at some point.
"The only reliable option is to make it easy to force initialization of all essential log4cxx static resources (like the default repo) to occur before the initialization of the static object that logs during its destructor.
Since objects are supposed to be destructed in reverse order of their construction (your mileage may vary based on your compiler) and you can control the relative initialization order within a compile unit by the placement, you may be able to force the defer the destruction of the repo by forcing its creation to occur before the constructor of your static object."
This I do not fully agree. Acording to my reading and understanding of the ISO C++ features while the compiler HAS to guarantee an exact order to construct and destruct objects from a single translation unit (ie in the same translation unit the static objects are constructed in the order of appearance and are destructed in the reversed order obviously) there is absolutely no guarantee to the order of constructors/destructors across different translation units. Considering that here we are talking about my codes (log4cxx user) and the log4cxx codes they are cleary at least 2 separate translation units. This means that the copiler and the C++ standard offer no guarantee that:
1. the constructors of the static objects of log4cxx are called before any of the static objects of my codes (this you might end up using uninitlized resources if in the constructors you use log4cxx)
2. the destructors of the static objects of log4cxx are called AFTER all the destructors of my static objects are finished (ie I might end up using invalid data)
AFAIK, to be able to manage this dependency issue (because it's a dependency issue, some static objects lifetime depends on other static object's lifetime) usually the user has to emply reference counters. The same problem for example is addressed with std::cin/cout/cerr/clog because they are 4 static iostream objects that need to be "constructed" before any of their users and also need to be destroyed after all of their users have finished. The solution employed usually with iostreams is like this: there is a header file included by all cin/cout/clog/cerr users, this header file declares something like "static iostreamreference reference;" meanging that all cin/cout/clog/cerr users get a iostreamreference object created in their own translation unit (as it's "static" in the header file) and this iostreamreference object in the constructor all it does is initilize the cin/cout/cerr/clog streams if not already and increment the usage count, and in the destructor decrements the user count and destroys them if count reaches 0.
Because I have seen that log4cxx already makes heavy usage of reference counted smart pointers (probably because it somewhat tries to emulate the log4j aproach) I thought to myself that just adding a reference count for the object used by the Logger's whould be enough and acording to my tests it solves the crash I got. Theoretically any object that is using the services of another object which lifetime is decoupled from the user (ie it is NOT created directly by the user and it is NOT destroyed directly by the user) needs to cache the pointers/references of the used object with a reference count mechanism through a Singleton-like interface to make sure the used object is created already when we need it and that is destroyed only after we don't need it anymore.
"Say if you have:
You could change it to:
which would force initialization of log4cxx to occur before the initialization of the static Foo. "
My users are just classes that embed a LoggerPtr object member initilized with log4cxx::getLogger from the constructor. As such there are already reference counter mechanisms (provided by LoggerPtr) that make sure that the Logger used by my object's constructors is alive as long as my object lives. And my experience proved that it indeed works nicely. The only problem is that there is a "blind shared pointer" to a static LoggerRepository object (Hierarcy) in each Logger, that might get destructed before every Logger gets destructed (because we have no guarantee that the static object destructors from the translation unit in log4cxx that included the static Hierarchy object are called after the destructors of my objects which might log using LoggerPtr that point to a Logger that uses the cached LoggerRepository pointer). As such, the example you provided shouldnt solve my problem either.
Hope I explained better now