Sign in to follow this  
Evil Steve

C++ Order Of Destruction

Recommended Posts

Me again [smile] As some of you might know, I'm trying to write a memory manager for my engine. However, as I found last night, the STL keeps hold of some memory that is only freed when a global variable inside a STL source file is destroyed. Now, I know that the order of construction / destruction isn't defined for global variables, and it appears that atexit() handlers fire before globals are destroyed. What I'd like to know is, is there any way I can have a function called after globals have been destroyed? For instance, at what point are DLLs unloaded? I could put something in a DLL if it'll work. There was an article I read somewhere that covered the order things are created and destroyed (The article was about writing your own loader I think), but I can't find it now. Platform specific answers are perfectly fine (Win32), I expect I'll need to do some crazy stuff to get this to work at all. Cheers, Steve

Share this post


Link to post
Share on other sites
I don't have a solution for you, but I'm interested in knowing which part of the STL is holding that memory and when it got allocated. Could you tell a bit more about this issue?

Share this post


Link to post
Share on other sites
Quote:
Original post by El Greco
I don't have a solution for you, but I'm interested in knowing which part of the STL is holding that memory and when it got allocated. Could you tell a bit more about this issue?
Sure, I made a post about this last night in My GDNet Journal.

Share this post


Link to post
Share on other sites
IIRC theres a gcc extension which lets you specify the priority of globals to control their construction order. That should let you do what you want I think.

Obviously this is non-portable though.

I've previously solved initialisation order problems with 'globals' being static within methods (eg. Obj& getObj() { static Obj o; return o; } ), however I have no idea if the destruction order of these objects is well defined or not.

Share this post


Link to post
Share on other sites
Quote:
Original post by OrangyTang
IIRC theres a gcc extension which lets you specify the priority of globals to control their construction order. That should let you do what you want I think.

Obviously this is non-portable though.

I've previously solved initialisation order problems with 'globals' being static within methods (eg. Obj& getObj() { static Obj o; return o; } ), however I have no idea if the destruction order of these objects is well defined or not.
Hmm, any idea if there's a MSVC version of that? I'll dig into the MSDN.

The globals being static in methods half works - but that causes the static to be created after the globals, meaning it's destroyed before them, which doesn't help.

The global in question is in STL code; I can't change that.


The first thing sounds exactly what I want, though.

Share this post


Link to post
Share on other sites
Do you have vs/vc++2k5 SP1 installed? the reason i ask is vc++2k5's string streams have memory leaks and the SP1 sorts it out as well as many other issues of course.

EDIT: There is another SP (which you install after SP1) if you're runing vs/vc++2k5 on Vista.

Share this post


Link to post
Share on other sites
Quote:
Original post by snk_kid
Do you have vs/vc++2k5 SP1 installed? the reason i ask is vc++2k5's string streams have memory leaks and the SP1 sorts it out as well as many other issues of course.

EDIT: There is another SP (which you install after SP1) if you're runing vs/vc++2k5 on Vista.
Nope, I don't have SP1 installed. For some reason I thought that was only for Express.

Just checked my code at work (VC2005 Express, SP1) and it has the same "leaks". These aren;t really leaks, because they do get freed up. Just after my memory manager...

I'm not running Vista on my dev machine(s), so that's not an issue.

Share this post


Link to post
Share on other sites
I'll poke around in your journal for the full story, but for what it's worth the way my old C++ memory tools worked was set up in such a way as to not track the memory allocated by the SC++L or other external tools, at least not explicitly; I only tracked allocations from code I actually wrote (which might include custom allocators to the SC++L objects, though).

I never ran into the problem you're describing, iirc. Although this was years ago, so perhaps the newer SC++L implementation shipping with modern compilers would exhibit the issue now.

EDIT: Okay. It's the call to new to allocate the facet (a facet is a term for an interface to a service provided by the locale library, for what it's worth) that is trapped by your manager and then reported as a leak, right?

The traditional, simple way to avoid this issue is to provide headers to enable/disable the #define macros you use to redirect new and delete (you do use macros for this, right?). It becomes a bit obnoxious to wrap your SC++L includes, or order them appropriately so they come into the translation unit before your macro, but it works. There are a few more way, possibly slightly cleaner, but they depend somewhat on the actual implementation detail of the system used to trap calls to new. Can you provide your code?

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
I'll poke around in your journal for the full story, but for what it's worth the way my old C++ memory tools worked was set up in such a way as to not track the memory allocated by the SC++L or other external tools, at least not explicitly; I only tracked allocations from code I actually wrote (which might include custom allocators to the SC++L objects, though).

I never ran into the problem you're describing, iirc. Although this was years ago, so perhaps the newer SC++L implementation shipping with modern compilers would exhibit the issue now.
Yeah, I chose to track STL allocations just so I'm catching everything.


Anyway, I've solved it. Thanks to mattd (See, TA can be useful sometimes [smile])
#pragma init_seg is what I needed. Adding this code forces my memory manager to be created before and destroyed after STL globals:

#pragma warning(disable:4074) // warning C4074: initializers put in compiler reserved initialization area
#pragma init_seg(compiler)
struct MemoryInitialiser
{
MemoryInitialiser() { PMemory::Create(); }
~MemoryInitialiser() { PMemory::Destroy(); }
} g_theMemoryInitialiser;



Thanks to all who helped [smile]

Share this post


Link to post
Share on other sites
Here are a few more solutions if anyone wants to stay away from compiler specific intrinsics.

1) Have the memory manager as a global object at the top of your main application. Obj files that are for the executable get initialized before library statics. Also, the the order of globals, within a compilation unit, are initialized from top down. If your memory manager is the first global variable in that file and doesn't depend, contain or inherit from any other class then you'll have it being initialized first.

2) The most portable way (I define portable being this has worked for me on the most platforms and most compilers) is to re-write the CRT initialization and shut down code. Have your own function get called instead of the CRT start up. You can do this through the linker option /ENTRY in visual studio. It's not too hard and most of the time you can copy and paste the compilers CRT code, remove the stuff you don't need, and stick your memory manager initialization before the global variables are constructed.

-= Dave

Share this post


Link to post
Share on other sites
Quote:
Original post by OrangyTang
I've previously solved initialisation order problems with 'globals' being static within methods (eg. Obj& getObj() { static Obj o; return o; } ), however I have no idea if the destruction order of these objects is well defined or not.

It is "relatively well defined". Static objects are destroyed in the inverse order of the completion of their constructor.

Share this post


Link to post
Share on other sites
Quote:
Original post by David Neubelt
1) Have the memory manager as a global object at the top of your main application. Obj files that are for the executable get initialized before library statics. Also, the the order of globals, within a compilation unit, are initialized from top down. If your memory manager is the first global variable in that file and doesn't depend, contain or inherit from any other class then you'll have it being initialized first.
I've tried this. The STL global is always constructed before any globals in my code, no matter what order the globals are defined in. Presumably it's in a lib init segment, so it's always constructed before user globals (Which makes sense, you don't want a user-defined global trying to use STL stuff and having it blow up).

Quote:
Original post by David Neubelt
2) The most portable way (I define portable being this has worked for me on the most platforms and most compilers) is to re-write the CRT initialization and shut down code. Have your own function get called instead of the CRT start up. You can do this through the linker option /ENTRY in visual studio. It's not too hard and most of the time you can copy and paste the compilers CRT code, remove the stuff you don't need, and stick your memory manager initialization before the global variables are constructed.
That's possible I suppose, but it's also pretty major overkill for this [smile]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this