home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c++.moderated      Moderated discussion of C++ superhackery      33,346 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 32,742 of 33,346   
   fmatthew5876 to Balog Pal   
   Re: Singletons   
   16 Dec 12 19:40:41   
   
   From: fmatthew5876@googlemail.com   
      
   On Sunday, December 16, 2012 10:27:05 AM UTC-5, Balog Pal wrote:   
   > On 12/14/2012 1:21 AM, Öö Tiib wrote:   
   >   
   > > First ... about your idea in general. Making unit tests is difficult   
   > > when singular state on what your unit depends is behind free functions   
   > > and you use some mocking framework that does not help turning free   
   > > functions into mock versions.   
   >   
   > Can you give a C++ example for this? IME you just use its regular   
   > header, then the linker obviously will miss the function body, and you   
   > provide an implementation.   
   >   
      
   I actually agree more the first poster here. Singletons do make creating   
   mock versions trivially easy if you use virtual functions.   
      
   In all other cases, yes you can just include the headers and provide   
   your own mock implementations but this may not be so straightforward. If   
   your code base is a library, you might be just linking small unit test   
   executables to it to do various tests. In this case without some   
   implementation specific compiler/linker hackery its not so easy to   
   replace the functions with mock versions.   
      
   > And you can help with the preprocessor too defining a macro for the   
   > function name that hijacks it. (the singleton accessor function shall   
   > have a unique name, right?)   
      
   Using the preprocessor here seems like a non-starter to me, especially   
   if you have nested namespaces or indirect access. One part may want to   
   access name::foo(), the other just foo(). The preprocessor also does not   
   help if you if you are testing code already compiled within your library.   
   In that case you really do want virtual or some kind of pimp idiom so   
   that the already compiled code just unknowingly calls your mock versions.   
      
      
   It looks like using a gate keeper such as getInstance() is very helpful   
   for some things:   
      
   If you want lazy initialization, using getInstance() is a great way to   
   do this. Nobody wants to write an initialization check to every single   
   method or trust that other developers will not forget to do so.   
      
   If you need thread safety, getInstance() could also return a class type   
   that not only provides singleton access but also locks a mutex. Once your   
   "singleton handle" is destroyed it can automatically free the lock in   
   the destructor.   
      
   And of course, enforcing the one-instance rule at compile time, which is what   
   this whole thing was developed for in the first place.   
      
   In my case I don't care at all about lazy initialization or thread safety. For   
   a game engine that is not going to be layered into other libraries, requiring   
   the user to call init() and shutdown() in order in the main function is not too   
   much to ask. Explicit initialization also means that the client can   
   pass parameters to the initialization routine, which is my case happens   
   to be configuration data parsed from config files and command line options.   
      
   Finally, a game engine with several sub systems such as graphics, physics,   
   audio, and ai, there is often a specific order things need to brought up and   
   torn down. Using lazy initialization makes this order hard to figure out and   
   easy to break.   
      
   Seeing as my requirements don't require a gate keeper, I'd rather simplify and   
   just have a global object I can call methods on or a set of free functions.   
      
   The disadvantage of a static global object is that now the data members and   
   private methods of the object have to be exposed in the header file. Every time   
   they change (which can be often, especially for private methods) everyone   
   including this header (which will be a lot of files, considering its a global)   
   has to recompile.   
      
   There are several options I could come up with to fixing the   
   recompilation issue:   
   1) Hide the data behind free functions   
   2) Use a global static object with only methods and no data, it can simply call   
   the methods of the real global singleton hidden in the implementation.   
   3) Make your exposed singleton a pure virtual base class a reference   
   or pointer.   
      
   3 is interesting because you can actually provide the one instance guarantee   
   at compile time by making the constructor and destructor protected. An exposed   
   global reference can easily be seated to a static version of the real subclass.   
   The cost of course being the overhead of virtual functions.   
      
      
   --   
         [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
         [ comp.lang.c++.moderated.    First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca