Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

benjamin bunny

Singleton/release build weirdness (VC++ 6)

This topic is 5405 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm using various singleton objects in my engine, all of which are based on the following template:
template <class T> 
class Singleton 
{
public:
	static T& inst()
	{
		static T instance;
		return instance;
	}
};
Classes derived from have private constructors, to ensure the class is really a singleton. They're declared like this
class Foo : public Singleton <Foo>
{
  friend Singleton<Foo>;
  Foo();
public:
  ...
}
This works fine, in debug mode, but when I turn on any optimisations in Visual C++ 6.0, my singleton classes' constructors are called multiple times. It turns out that subsequent calls to inst() after the first call the constructor, even though a static variable is used to instantiate the singleton object. The end result is there are 3 copies of the application, 2 copies of the texture manager, and my program crashes out spectacularly. On further investigation, it appears that although the constructors are called multiple times, the this pointer points to the same block of memory. The problem doesn't occur if I do the same thing without templates. Is this some kind of weird bug with Visual C++'s template support? Has anyone encountered it before? Is VC++ .net likely to fix the problem? ____________________________________________________________ www.elf-stone.com [edited by - benjamin bunny on August 7, 2003 8:08:22 AM]

Share this post


Link to post
Share on other sites
Advertisement
What''s happening is that when optimisations are turned on, inst() is getting inlined, as expected. What isn''t expected, is that a different T instance is generated for every translation unit (.cpp) file that inst() appears in.

This is because the static keyword only applies to the translation unit. When inlining is disabled, the inst() function is only generated once as a normal (not inlined) function, and therefore there is only a single T instance. But when inlining is enabled, multiple inst() functions are generated for every time it''s called. In any one translation unit, there can end up being multiple inlined T instance declarations of which only 1 is kept since they''re static. The problem is that 1 is kept for every translation unit.

Now that you know what''s going wrong, try using this instead

template <class T>
class Singleton
{
static T instance;
public:
static T& inst()
{
return instance;
}
};

template <class T>
T Singleton<T>::instance;

Since it''s templated you can safely define the static member in the header, the compiler will ensure only 1 copy exists. I use this and haven''t ran into any problems with it.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
try making the Foo constructor private and see what it throws up.

Share this post


Link to post
Share on other sites
quote:

try making the Foo constructor private and see what it throws up.


class Foo : public Singleton <Foo>
{
friend Singleton<Foo>; // <--- !!!

Foo();
public:
...
}

Happy birthday?

Share this post


Link to post
Share on other sites
By the way, the behaviour joanusdmentia described is only a bug in VC6. Well, it won''t comfort you much since you likely have no choice. I just wanted to let you know it''s not the standard defined behaviour.

Share this post


Link to post
Share on other sites
joanusdmentia: Thanks for the explanation. However your solution doesn''t work, because it doesn''t allow me to control the initialisation order of the singleton classes. (For example, with my code I can call App::inst() from my texture manager constructor and guarantee the application window is available before I try to load any textures. )

I guess the solution is to turn off optimisation for that block of code. Any idea how to do that with VC 6?

quote:
Original post by civguy
By the way, the behaviour joanusdmentia described is only a bug in VC6. Well, it won''t comfort you much since you likely have no choice. I just wanted to let you know it''s not the standard defined behaviour.


Yeah, I thought that behaviour was a bit unintuitive. Any idea if this is fixed in VC .net? I have a steadily growing list of complaints with the VC6 compiler, and I''ll ditch it as soon as I have a good excuse.

____________________________________________________________
www.elf-stone.com

Share this post


Link to post
Share on other sites
How about if you try:


template<class T>
class Singleton
{
static T *instance;

public:
static T& inst()
{
if (!instance) {
instance = new T;
atexit(_destroy);
}
return *instance;
}
static void _destroy()
{
delete instance;
}
};

template<class T> T *Singleton<T>::instance = NULL;


edit: using atexit to schedule destruction

[edited by - fizban75 on August 7, 2003 10:16:35 AM]

Share this post


Link to post
Share on other sites
I''ve written an article on code project about this. Use the code however you want (as long as I can keep using it!)

Cheers,

Paul

http://www.codeproject.com/useritems/pdesingletontemplatenomfc.asp


P.S. If you like the article rate it nice and high ;-)

Share this post


Link to post
Share on other sites
quote:
I guess the solution is to turn off optimisation for that block of code. Any idea how to do that with VC 6?


In VC 6 you can use

#pragma auto_inline(off)

before and

#pragma auto_inline(on)

after your inst() function.

Share this post


Link to post
Share on other sites
Singletons and static variables defined in functions have both always confused me a lot, but it seems to me that instead of jumping through hoops to turn off your inlining, you could just define the body of the inst() function in the .cpp file? I''m sure with this many smart people, someone else has thought of it and figured out a flaw with it...

Also, just what purpose does static have when used on a local variable? It is my understanding that static makes variables one-per-translation-unit, but a local gets deallocated at return anyways, so isn''t it redundant?

--------------------


You are not a real programmer until you end all your sentences with semicolons; (c) 2000 ROAD Programming

You are unique. Just like everybody else.

"Mechanical engineers design weapons; civil engineers design targets."
"Sensitivity is adjustable, so you can set it to detect elephants and other small creatures." -- Product Description for a vibration sensor

Yanroy@usa.com

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!