be4c6be8   
   From: daniel.kruegler@googlemail.com   
      
   Am 26.01.2012 20:49, schrieb paul_71:   
   [..]   
   > Yes, this is a commonly used idiom of "registrars" for e.g.   
   > deserialization object factories... Unfortunately it is very easy to   
   > break on every implementation I have tried. If such non-locals as the   
   > "sc" from your example live in "static libraries" then the applied   
   > linker optimization strategies are not able to see the side effects of   
   > "sc" constructors. In your example, whenever a linker sees a usage of   
   > "sc" (as in sc.SomeFunction()) the constructor for sc will be run. If   
   > it does not, the symbol "sc" is just removed and the program behaves   
   > as it would not be present.   
      
   As explained in my reply, this is easy to fix for static libraries in   
   practice. Just define a static variable in every *header* of the library   
   where the constructor calls a single time a function local static   
   variable. Here a sketch:   
      
   // register_api.h: (Needed for registration)   
      
   namespace api {   
      
   template   
   class RegistryProxy;   
      
   namespace details {   
      
   class Registry   
   {   
    template   
    friend class api::RegistryProxy;   
      
    Registry(const char* id);   
   };   
      
   } // details   
      
   template   
   class RegistryProxy   
   {   
    static details::Registry& init(const char* id) {   
    static details::Registry result(id);   
    return result;   
    }   
   public:   
    RegistryProxy(const char* id) { init(id); }   
   };   
      
   }   
      
   // query_api.h: (needed to check the registry contents)   
      
   #include    
   #include    
      
   namespace api {   
      
   typedef std::vector ContType;   
      
   ContType allIds();   
      
   }   
      
   // register_lib.cpp   
   #include "register_api.h"   
   #include "query_api.h"   
      
   namespace api {   
      
   namespace details {   
   namespace {   
      
   inline ContType& ids()   
   {   
    static ContType result;   
    return result;   
   }   
      
   } // anon   
      
   Registry::Registry(const char* id)   
   {   
    ids().push_back(id);   
   }   
      
   } // details   
      
   ContType allIds()   
   {   
    return details::ids();   
   }   
      
   } // api   
      
   Now lets consider a static library user_api, which provides an api header:   
      
   //user_api.h:   
      
   #include "user_api_register.h"   
      
   namespace user_api {   
      
   // Something to export   
      
   }   
      
   // user_api_register.h (internally needed to ensure proper registration)   
   #include "register_api.h"   
      
   namespace user_api {   
   namespace details {   
      
   class UserType;   
      
   namespace {   
    api::RegistryProxy force_registration_do_not_use("user_api");   
   }   
      
   }   
   }   
      
   Finally we have a test program that depends on the static user library   
   and does show the registry contents:   
      
   #include    
   #include    
   #include    
   #include "query_api.h"   
      
   #include "user_api.h" // This could have been included by any other   
    // TU of the main program. For simplicity it   
    // is included here.   
      
   int main()   
   {   
    api::ContType ids = api::allIds();   
    std::copy(ids.begin(), ids.end(),   
   std::ostream_iterator(std::cout, "\n"));   
   }   
      
   Greetings from Bremen,   
      
   Daniel Krügler   
      
      
   --   
    [ 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)   
|