From: Chris Newbold (Chris.Newbold_at_[hidden])
Date: 2008-07-08 16:17:32
> From: boost-bounces_at_[hidden] [mailto:boost-bounces_at_[hidden]]
> On Behalf Of Phil Bouchard
> Sent: Tuesday, July 08, 2008 1:46 AM
> "Chris Newbold" <Chris.Newbold_at_[hidden]> wrote in message
> > Just for grins, try printing a message out from the destructor of
> > owned_base::pool (or setting a breakpoint there) and see how many times
> > you wind up there. My hunch is that this is an ODR issue...
> I get the following:
> BTW I have gotten the same problem by using Gcc 4.3 and I am not linking
> multiple source files. Here is my build process:
> $ g++ shifted_ptr_test2.cpp -I ../../..
I've been able to reproduce this failure in my local sandbox, using GCC 4.1.2. My initial ODR hypothesis was not right, but was close: we're having a static-initialization ordering issue.
Pool's fast_pool_allocator class uses singleton_pool to manage a single underlying pool based on the requested size. Singleton_pool in turn uses singleton_default (found in pool/detail/singleton.hpp) which tries _really_ hard to force the compiler to construct the controlled instance at just the right time.
What's happening in your test case is that the namespace-scoped owned_base::pool instance (line 187 in sh_owned_base_nt.hpp) is actually being constructed by the compiler _before_ the namespace-scoped initializer object (called create_object, at line 95 in pool/detail/singleton.hpp). That in turn results in the compiler destructing the singleton pool _before_ destructing your owned_base::pool instance. Thus the memory containing the list nodes of the two std::list instanced contained in owned_base::pool is has been freed by the time the list destructors run.
I'm a little hard-pressed to make a call as to whether the problem is with GCC's initialization ordering or whether the "cleverness" in pool/detail/singleton.hpp is simply bankrupt and is trying to guarantee something which the language standard cannot.
The namespace-scoped initializer generated in pool/detail/singleton.hpp lexically precedes the declaration of the client in sh_owned_base_nt.hpp. Since this test case is a single translation unit, this should in theory ensure that the former is constructed before the latter. However, there's some indirection and function-scoped static objects in play here, too, which may render that guarantee meaningless.
I'd be interested to get some additional eyes on the code in pool/detail/singleton.hpp (there's a decent comment there about how it's supposed to work) and see if there can be a reasonable expectation for it to work on a conforming compiler...
Boost list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk