
From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Joaquin M Lopez Munoz Sent: Tuesday, July 08, 2008 6:06 PM
Thanks for your detailed analysis, Joaquin. I have a few comments/questions which are interspersed below...
* pool/detail/singleton.hpp claims that singleton_default<T>::instance() is automatically called before main() if no user code does it explicitly. Strictly speaking, the implementation does not guarantee this, but only that singleton_default<T>::instance() will be called during the so-called dynamic initialization phase of the program startup sequence. For all practical purposes, however, this is equivalent to the orignal claim, so the problem does not lie here.
Right. The way that singleton_default guarantees that instance() is called during dynamic initialization is by declaring a global object-- an instance of singleton_default<T>::object_creator (around line 95 of singleton.hpp). The controlled instance is created by the first of: 1. A call to instance() from application code attempting to use the pool or 2. The construction (during dynamic initialization) of object_creator.
* Where the problem lies can be found by looking at the usage of singleton_pool by fast_pool_allocator: notice that singleton_pool is used *only* when fast_pool_allocator::allocate or ::deallocate are invoked. So, it is perfectly possible to construct a fast_pool_allocator without that forcing the compiler to construct the underying singleton_pool *yet*. And this is what's happening indeed, the sequence of objects construction we're having is this:
1. owned_base::pool_ begins construction 1.1 call of new pool_lii() inside pool::pool 1.1.1 a fast_pool_allocator is cted inside pool_lii ctor. 1.2 pool_ii ends construction 2. pool_ ends construction 3. the singleton instance associated to singleton_pool<...>is cted before main() because fast_pool_allocator uses it later (singleton guarantee).
I'm not sure I buy this explanation entirely. owned_base::pool_ is a global object. As described above, so is object_creator. The test case consists of a single translation unit, and inside that translation unit, the declaration of object_creator precedes that of owned_base::pool_ (because object_creator is declared by a Boost.Pool header which is included before the application-level code which declares owned_base). Following the fairly clear rules about initialization order for namespace-scoped global objects, I would have expected the compiler to construct object_creator first (and therefore the pool) before constructing owned_base::pool_. I'm not at all convinced that singleton_default or fast_pool_allocator is actually correct, but I do think this situation is a bit more complex... -Chris