   Singleton/release build weirdness (VC++ 6)
  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]
  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.;  try making the Foo constructor private and see what it throws up. ;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? ;  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. ;  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;  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];  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,Paulhttp://www.codeproject.com/useritems/pdesingletontemplatenomfc.aspP.S.  If you like the article rate it nice and high ;-) ;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. ;  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 sensorYanroy@usa.com 