From: Chris Newbold (Chris.Newbold_at_[hidden])
Date: 2008-07-11 10:25:10
> From: boost-bounces_at_[hidden] [mailto:boost-bounces_at_[hidden]]
> 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
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...
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk