From: SourceForge.net <no...@so...> - 2006-02-28 13:05:20
|
Feature Requests item #1437986, was opened at 2006-02-24 11:33 Message generated for change (Settings changed) made by syntheticpp You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=396647&aid=1437986&group_id=29557 Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: None Group: None >Status: Closed Priority: 5 Submitted By: Marcus Lindblom (fizzgig) >Assigned to: Peter Kuemmel (syntheticpp) Summary: Ability to use SingletonHolder in DLL on Win32 Initial Comment: This amounts to adding the usual machinery for adding __declspec(import) or __declspec(export) (or nothing, if linking statically) to datatypes/functions. I've done this myself, to an old loki version: Singleton.h : #ifndef LOKI_SINGLETON_DECLSPEC #define LOKI_SINGLETON_DECLSPEC #endif namespace Private { class LOKI_SINGLETON_DECLSPEC LifetimeTracker { ... }; LOKI_SINGLETON_DECLSPEC extern TrackerArray pTrackerArray; LOKI_SINGLETON_DECLSPEC extern unsigned int elements; LOKI_SINGLETON_DECLSPEC void LOKI_ATEXITFN_CALLING_CONVENTION AtExitFn(); } .. and similar for Singleton.cpp. In order to use this from my DLL (into which the Loki-functions are compiled/linked), I define LOKI_SINGLETON_DECLSPEC as the same prefix I use for the dll's other functions. This seem to work okay for me. The attached source is a modified version of the CVS at around 2005-03-07 (I intend to update to 0.1.3 soon), just for reference. ---------------------------------------------------------------------- Comment By: Peter Kuemmel (syntheticpp) Date: 2006-02-28 11:46 Message: Logged In: YES user_id=1159765 Sorry, my last post was not valid code, but it was the beginning of the following solution which I've commited to cvs (see test/SingletonDll): There is a Foo class in Foo.dll. There is a Foo singleton object which is exported by SingletonDll.dll. A client (Client.cpp) gets the singleton object from SingletonDll.dll. --------------------- code extracts Foo.h: class Foo declaration Foo.cpp: class Foo definition SingletonDll.h: #include "singletondll_export.h" class Foo; // Use the predefined Loki::Singleton // and export Loki::Singleton<Foo> #include <loki/Singleton.h> template class SINGLETONDLL_EXPORT Loki::Singleton<Foo>; SingletonDll.cpp: #include <singletondll.h> #include "foo.h" typedef Loki::SingletonHolder<Foo> FooSingleton; LOKI_SINGLETON_INSTANCE_DEFINITION(FooSingleton) /* // code generated by the macro: Foo& Loki::Singleton<Foo>::Instance() { return FooSingleton::Instance(); }; */ client.cpp: #include "singletondll.h" #include "foo.h" int main() { Foo& lokifoo = Loki::Singleton<Foo>::Instance(); lokifoo.foo(); } ---------------------------------------------------------------------- Comment By: Marcus Lindblom (fizzgig) Date: 2006-02-27 15:59 Message: Logged In: YES user_id=197414 Hm. I'm not sure I follow you entirely on the last part. What I had to do to get this working was to write a bit more than I intended from my previous post. One has to give the full definition of the specialised Singleton<>-struct in the header declaring the Singleton-class (i.e. Foo) (which is quite obvious when you think about it ;-). So there's a bit of copy-paste involved that I don't like (using a simple function instead of a struct fixes that, however, so I think that's probably the easiest solution.) One could always use a specialisation, i.e. 'T& GetSingleton<T>()', so that you still get one way of accessing singletons of different types. I think that is the best way of solving this. ---------------------------------------------------------------------- Comment By: Peter Kuemmel (syntheticpp) Date: 2006-02-24 15:44 Message: Logged In: YES user_id=1159765 O.K., Foo& foo = Singleton<Foo>::Instance(); (or your typedef version) is more informative, and it looks more like the already known usage of a Singleton typedef: typedef SingletonHolder<..> Singleton; Foo& foo = Singleton::Instance(); Maybe we should add your structure to Loki: (all functions are upper case in Loki) loki/Singleton.h: namespace Loki { template<typename T> struct Singleton<T> { typedef T & Type; static Type Instance(); }; } and a new header file which should only be included by the file defining the SingletonHolder (here the template parameter T_Holder). loki/Singleton_def.h: namespace Loki { template<typename T_Holder> Singleton<T_Holder>::Type Singleton<T_Holder>::Instance() { return T_Holder::Instance(); } } What do you think? ---------------------------------------------------------------------- Comment By: Marcus Lindblom (fizzgig) Date: 2006-02-24 15:05 Message: Logged In: YES user_id=197414 I have added a typedef to the original singleton: template<typename T> struct Singleton<T> : noncopyable { typedef T type; static type& instance(); static type& the(); ///< this is what I use }; So, if I then have: typedef Singleton<FooImpl> Foo; I can write: Foo::type& foo = Foo::the(); foo.x(); foo.y(); I like this style as it reduces code-clutter. ---------------------------------------------------------------------- Comment By: Peter Kuemmel (syntheticpp) Date: 2006-02-24 14:53 Message: Logged In: YES user_id=1159765 I like your adiea to standarizze the I like your idea to standardize the way of accessing the holded object, good suggestion! But why do you prefer a additional struct? Why not using a template function: template<T> T& MYLIB_DECLSPEC getInstance(); ---------------------------------------------------------------------- Comment By: Marcus Lindblom (fizzgig) Date: 2006-02-24 14:36 Message: Logged In: YES user_id=197414 I think it is still quite elegant, as it allows you to precisely (spl?) define the creation and destruction semantics for a singleton object, and not worry about it. This is what I think the true beauty of the Loki-singleton. Frankly, IMHO, having a big typedef in a header and forcing every compilation unit to instantiate all the singleton-template-code, is not very elegant (from a physical design perspective), at least not for larger cpp-projects. It might be solvable via some kind of template specialization, so that one can do something like this: singleton.h: template<typename T> struct Singleton<T> : noncopyable { static T& instance(); } .h: class FooImpl { }; typedef Singleton<FooImpl> Foo; template<> class MYLIB_DECLSPEC Singleton<Fooimpl>; .cpp: template<> class Singleton<Fooimpl> { static FooImpl& instance () { return SingletonHolder<FooImpl, ...>::instance(); } } ---------------------------------------------------------------------- Comment By: Peter Kuemmel (syntheticpp) Date: 2006-02-24 14:26 Message: Logged In: YES user_id=1159765 Singletons and Dlls: this is a general problem. And I don't know a better solution than yours: adding a getSingletonInstance somewhere in the code. But then most of the elegance of the Singleton template-solution is gone. Peter ---------------------------------------------------------------------- Comment By: Marcus Lindblom (fizzgig) Date: 2006-02-24 14:18 Message: Logged In: YES user_id=197414 Ok. I jumped to conclusion a bit too fast. The above obviously only fixes the link-problem of the AtExit-function and related data. The attached code will not work properly when an typedeffed singleton is referenced from the client module (i.e. not the dll) in some cases, i.e. when the singleton data is dynamically linked (i.e. ptr and isDestroyed flag). Then, one will have two singletons. The problem is that the SingletonHolder<xx> data needs to have _declspec conforming to the declaring dll's import/export status, so that only one instance exists across module boundaries. One can work around this this by exporting a small function whose hidden implementation returns SingletonHolder<xyz>::Instance(). This has the added benefit of reducing compile time due to includes and template-instantiations for clients. (Perhaps one can create something called SingletonProxy<T> that automates much of this.) I'll continue checking to see if I can do something really good, but as I do not think one can apply __declspec to typedefs, nor choose it based on types, the above workaround might be the only way. ---------------------------------------------------------------------- Comment By: Marcus Lindblom (fizzgig) Date: 2006-02-24 12:35 Message: Logged In: YES user_id=197414 I'll see what I can do. Note that as the only non-template stuff I use is Singleton.cpp, I can only add patch/test that. But I'll try do write something generic so that you can apply it to other parts. W.r.t. that warning, I sometimes get that when it isn't warranted (i.e. on a std::vector member of a dll-exported-class). Especially OpenSG spits out heaps of those warnings, and, from my experience, it works very well anyway. (so I've disabled that warning) :-) I have only needed it on template code where I have hidden the specialization (and thus am actually dll-linking to those functions). I think it's not as much an issue if both dll and client has access to the full implementation and are using the same runtime libs (i.e. debug/release of msvcrt). ---------------------------------------------------------------------- Comment By: Peter Kuemmel (syntheticpp) Date: 2006-02-24 11:49 Message: Logged In: YES user_id=1159765 Great! Recently there was a similar request: https://sourceforge.net/tracker/index.php?func=detail&aid=1431456&group_id=29557&atid=396644 (seems he needs the declspec also in the pure tempate functions) When you intend to update to 0.1.3 is it possible to use the cvs version instead? Before committing we also need some small test code which will be added to /test. Thanks, Peter ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=396647&aid=1437986&group_id=29557 |