Hi All, I have been writing a wrapper around the variate_generator as I always want to use the same number generator, but do want to use different distributions. As I want to use only one instance of the engine instance for all instanced of my random number generator class, I used a singleton pattern. as is my first time using it, I decided to test it generously, to try and see if the same instance of the enigine is used. So not only did i check if the engine pointer for different instances of my random class is the same, but i also checked if the destructor for the engine (does not) get called (i've added a constructor to the boost header file temporarily) and whether the random numbers generated are indeed not the same. It seems my code does not work, the destructor gets called weirdly often, e.g., 4 times every time i initialize my random class. Also, the numbers generated by the two generators are the same, indicating the engine is reinitialized for every instance of my random class. Yet, the pointer to the engine is the same (note that it is also the same if i dont call the destructor in between). I am using MSVC 2008 on windows XP 32 bit. What am I doing wrong? As I am learning, any other feedback is also very welcome. Best, Diederick ---- output of run of code below: check 0 00000000 ctor 1 destructor destructor destructor destructor after ctor 1 003462E0 random: 8148 dtor 1 destructor ctor 2 destructor destructor destructor destructor after ctor 2 003462E0 random: 8148 destructor destructor ---- code // includes #include <boost/random.hpp> #include <time.h> #include <iostream> using namespace std; // declaration template<class Dist> class CRandom { public: /** use for Dist: CRandomI Ci(min,max); uses uniform_int<int> - integral types CRandomR Cr(min,max); uses uniform_real<double> - floating point types for other ditributions or types, use: CRandom<distribution<optional type>> Cr(0--3 params, depending on distribution); for distributions and params, see: http://www.boost.org/doc/libs/1_39_0/libs/random/random-distributions.html */ // forwarding constructors explicit CRandom() : Gen(*EngineSingleton::Eng(), Dist()) { } template<class P> explicit CRandom(const P & p1) : Gen(*EngineSingleton::Eng(), Dist(p1)) { } template<class P> explicit CRandom(const P & p1, const P & p2) : Gen(*EngineSingleton::Eng(), Dist(p1, p2)) { } template<class P> explicit CRandom(const P & p1, const P & p2, const P & p3) : Gen(*EngineSingleton::Eng(), Dist(p1, p2, p3)) { } ~CRandom(void) {}; typedef typename Dist::result_type result_type; result_type operator()() { return Gen(); } template<class T> result_type operator()(T value) { return Gen(value); } private: boost::variate_generator<boost::mt19937,Dist> Gen; }; // end declaration // shorthand typedefs typedef CRandom<boost::uniform_int<int>> CRandomI; // even int is default type , specify it in case it ever changes typedef CRandom<boost::uniform_real<double>> CRandomR; // even double is default type, specify it in case it ever changes /** engine wrapper class following singleton pattern, so every instantiation of CRandom uses the same engine based on: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf */ // declaration class EngineSingleton { public: static boost::mt19937* Eng(); static boost::mt19937* GetEngPoint() {return pEng;}; // for test only protected: // disallow (copy) construction and assignment operator EngineSingleton(); EngineSingleton(const EngineSingleton&); EngineSingleton& operator=(const EngineSingleton&); private: static boost::mt19937* pEng; }; // end declaration // implementation boost::mt19937* EngineSingleton::pEng = NULL; boost::mt19937* EngineSingleton::Eng() { if (pEng == NULL) { pEng = new boost::mt19937(/*unsigned int(time(NULL))*/); // initialize with same seed always, for test only } return pEng; } // end implementation //main int main(int argc, char* argv[]) { cout << "check 0" << endl; cout << EngineSingleton::GetEngPoint() << endl; cout << "ctor 1" << endl; CRandomI Cr(1,10000); cout << "after ctor 1" << endl; cout << EngineSingleton::GetEngPoint() << endl; int test = Cr(); cout << "random: " << test << endl; cout << "dtor 1" << endl; Cr.~CRandom(); cout << "ctor 2" << endl; CRandomI Cr2(1,10000); cout << "after ctor 2" << endl; cout << EngineSingleton::GetEngPoint() << endl; int test2 = Cr2(); cout << "random: " << test2 << endl; // exit return 1; }
Hi Diederick, You may take a look at the following link for the discussion of generic Singleton pattern with testing code, so far the best one I have ever read about Singleton pattern: http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton... I hope this helps, Robert On Sat, Jul 25, 2009 at 10:44 PM, Diederick C. Niehorster <dcnieho@gmail.com
wrote:
Hi All,
I have been writing a wrapper around the variate_generator as I always want to use the same number generator, but do want to use different distributions. As I want to use only one instance of the engine instance for all instanced of my random number generator class, I used a singleton pattern. as is my first time using it, I decided to test it generously, to try and see if the same instance of the enigine is used. So not only did i check if the engine pointer for different instances of my random class is the same, but i also checked if the destructor for the engine (does not) get called (i've added a constructor to the boost header file temporarily) and whether the random numbers generated are indeed not the same.
It seems my code does not work, the destructor gets called weirdly often, e.g., 4 times every time i initialize my random class. Also, the numbers generated by the two generators are the same, indicating the engine is reinitialized for every instance of my random class. Yet, the pointer to the engine is the same (note that it is also the same if i dont call the destructor in between).
I am using MSVC 2008 on windows XP 32 bit.
What am I doing wrong? As I am learning, any other feedback is also very welcome.
Best, Diederick ---- output of run of code below: check 0 00000000 ctor 1 destructor destructor destructor destructor after ctor 1 003462E0 random: 8148 dtor 1 destructor ctor 2 destructor destructor destructor destructor after ctor 2 003462E0 random: 8148 destructor destructor
---- code // includes #include <boost/random.hpp> #include <time.h> #include <iostream> using namespace std;
// declaration template<class Dist> class CRandom { public: /** use for Dist: CRandomI Ci(min,max); uses uniform_int<int> - integral types CRandomR Cr(min,max); uses uniform_real<double> - floating point types
for other ditributions or types, use: CRandom<distribution<optional type>> Cr(0--3 params, depending on distribution); for distributions and params, see: http://www.boost.org/doc/libs/1_39_0/libs/random/random-distributions.html */
// forwarding constructors explicit CRandom() : Gen(*EngineSingleton::Eng(), Dist()) { } template<class P> explicit CRandom(const P & p1) : Gen(*EngineSingleton::Eng(), Dist(p1)) { } template<class P> explicit CRandom(const P & p1, const P & p2) : Gen(*EngineSingleton::Eng(), Dist(p1, p2)) { } template<class P> explicit CRandom(const P & p1, const P & p2, const P & p3) : Gen(*EngineSingleton::Eng(), Dist(p1, p2, p3)) { }
~CRandom(void) {};
typedef typename Dist::result_type result_type;
result_type operator()() { return Gen(); } template<class T> result_type operator()(T value) { return Gen(value); }
private: boost::variate_generator<boost::mt19937,Dist> Gen; }; // end declaration
// shorthand typedefs typedef CRandom<boost::uniform_int<int>> CRandomI; // even int is default type , specify it in case it ever changes typedef CRandom<boost::uniform_real<double>> CRandomR; // even double is default type, specify it in case it ever changes
/** engine wrapper class following singleton pattern, so every instantiation of CRandom uses the same engine based on: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf */ // declaration class EngineSingleton { public: static boost::mt19937* Eng(); static boost::mt19937* GetEngPoint() {return pEng;}; // for test only protected: // disallow (copy) construction and assignment operator EngineSingleton(); EngineSingleton(const EngineSingleton&); EngineSingleton& operator=(const EngineSingleton&); private: static boost::mt19937* pEng; }; // end declaration
// implementation boost::mt19937* EngineSingleton::pEng = NULL;
boost::mt19937* EngineSingleton::Eng() { if (pEng == NULL) { pEng = new boost::mt19937(/*unsigned int(time(NULL))*/); // initialize with same seed always, for test only } return pEng; } // end implementation
//main int main(int argc, char* argv[]) { cout << "check 0" << endl; cout << EngineSingleton::GetEngPoint() << endl;
cout << "ctor 1" << endl; CRandomI Cr(1,10000); cout << "after ctor 1" << endl; cout << EngineSingleton::GetEngPoint() << endl; int test = Cr(); cout << "random: " << test << endl;
cout << "dtor 1" << endl; Cr.~CRandom();
cout << "ctor 2" << endl; CRandomI Cr2(1,10000); cout << "after ctor 2" << endl; cout << EngineSingleton::GetEngPoint() << endl; int test2 = Cr2(); cout << "random: " << test2 << endl;
// exit return 1; } _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Hi Kevin, Thank you for your suggestions, I have learned from your code but don't think it is optimally suited for my needs. Hi Robert, Thank you for the tip, however, it seems not possible to seed my engine during construction (that is call the constructor with an parameter) with your singleton class. Hi Boost lzw, Thats a great article, I'll study it and probably use that code as it seems flexible and suitable for my needs (after a quick glance). In general, wouldn't it be a good idea to have a singleton library inside boost? To my understanding they are used quite often, so better provide the world with a (few) good implementation(s suited for different needs). What do you think? Best, Diederick On Sun, Jul 26, 2009 at 11:15 AM, Boost lzw<boostlzw@gmail.com> wrote:
Hi Diederick,
You may take a look at the following link for the discussion of generic Singleton pattern with testing code, so far the best one I have ever read about Singleton pattern: http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton...
I hope this helps, Robert
On Sat, Jul 25, 2009 at 10:44 PM, Diederick C. Niehorster <dcnieho@gmail.com> wrote:
Hi All,
I have been writing a wrapper around the variate_generator as I always want to use the same number generator, but do want to use different distributions. As I want to use only one instance of the engine instance for all instanced of my random number generator class, I used a singleton pattern. as is my first time using it, I decided to test it generously, to try and see if the same instance of the enigine is used. So not only did i check if the engine pointer for different instances of my random class is the same, but i also checked if the destructor for the engine (does not) get called (i've added a constructor to the boost header file temporarily) and whether the random numbers generated are indeed not the same.
It seems my code does not work, the destructor gets called weirdly often, e.g., 4 times every time i initialize my random class. Also, the numbers generated by the two generators are the same, indicating the engine is reinitialized for every instance of my random class. Yet, the pointer to the engine is the same (note that it is also the same if i dont call the destructor in between).
I am using MSVC 2008 on windows XP 32 bit.
What am I doing wrong? As I am learning, any other feedback is also very welcome.
Best, Diederick ---- output of run of code below: check 0 00000000 ctor 1 destructor destructor destructor destructor after ctor 1 003462E0 random: 8148 dtor 1 destructor ctor 2 destructor destructor destructor destructor after ctor 2 003462E0 random: 8148 destructor destructor
---- code // includes #include <boost/random.hpp> #include <time.h> #include <iostream> using namespace std;
// declaration template<class Dist> class CRandom { public: /** use for Dist: CRandomI Ci(min,max); uses uniform_int<int> - integral types CRandomR Cr(min,max); uses uniform_real<double> - floating point types
for other ditributions or types, use: CRandom<distribution<optional type>> Cr(0--3 params, depending on distribution); for distributions and params, see: http://www.boost.org/doc/libs/1_39_0/libs/random/random-distributions.html */
// forwarding constructors explicit CRandom() : Gen(*EngineSingleton::Eng(), Dist()) { } template<class P> explicit CRandom(const P & p1) : Gen(*EngineSingleton::Eng(), Dist(p1)) { } template<class P> explicit CRandom(const P & p1, const P & p2) : Gen(*EngineSingleton::Eng(), Dist(p1, p2)) { } template<class P> explicit CRandom(const P & p1, const P & p2, const P & p3) : Gen(*EngineSingleton::Eng(), Dist(p1, p2, p3)) { }
~CRandom(void) {};
typedef typename Dist::result_type result_type;
result_type operator()() { return Gen(); } template<class T> result_type operator()(T value) { return Gen(value); }
private: boost::variate_generator<boost::mt19937,Dist> Gen; }; // end declaration
// shorthand typedefs typedef CRandom<boost::uniform_int<int>> CRandomI; // even int is default type , specify it in case it ever changes typedef CRandom<boost::uniform_real<double>> CRandomR; // even double is default type, specify it in case it ever changes
/** engine wrapper class following singleton pattern, so every instantiation of CRandom uses the same engine based on: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf */ // declaration class EngineSingleton { public: static boost::mt19937* Eng(); static boost::mt19937* GetEngPoint() {return pEng;}; // for test only protected: // disallow (copy) construction and assignment operator EngineSingleton(); EngineSingleton(const EngineSingleton&); EngineSingleton& operator=(const EngineSingleton&); private: static boost::mt19937* pEng; }; // end declaration
// implementation boost::mt19937* EngineSingleton::pEng = NULL;
boost::mt19937* EngineSingleton::Eng() { if (pEng == NULL) { pEng = new boost::mt19937(/*unsigned int(time(NULL))*/); // initialize with same seed always, for test only } return pEng; } // end implementation
//main int main(int argc, char* argv[]) { cout << "check 0" << endl; cout << EngineSingleton::GetEngPoint() << endl;
cout << "ctor 1" << endl; CRandomI Cr(1,10000); cout << "after ctor 1" << endl; cout << EngineSingleton::GetEngPoint() << endl; int test = Cr(); cout << "random: " << test << endl;
cout << "dtor 1" << endl; Cr.~CRandom();
cout << "ctor 2" << endl; CRandomI Cr2(1,10000); cout << "after ctor 2" << endl; cout << EngineSingleton::GetEngPoint() << endl; int test2 = Cr2(); cout << "random: " << test2 << endl;
// exit return 1; } _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Hi All, My code has now become what is pasted below. It does the trick and allows for singletons with a parameterized constructor. This leaves the question of whether a singleton library would be a useful addition to boost. I would be willing to code and write, though this would be a learning process for me. Best, Diederick ----- singleton class: --- #pragma once // Meyers singleton with support for constructors with 1 parameter // http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton... // http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton... // http://www.devarticles.com/c/a/Cplusplus/The-Singleton-Pattern-Revisited/ // http://www.cplusplus.com/forum/beginner/1459/ template <class T> class Singleton { public: static T& Instance() { static T _instance; return _instance; } template<class P> static T& Instance(const P & p) { static T _instance(p); return _instance; } private: Singleton(); // ctor hidden ~Singleton(); // dtor hidden Singleton(Singleton const&); // copy ctor hidden Singleton& operator=(Singleton const&); // assign op hidden }; ---- Random number class with default engine: ---- #pragma once // includes #include <boost/random.hpp> #include <time.h> #include <iostream> #include "Singleton.h" // namespaces namespace s = std; namespace b = boost; // declaration template<class Dist> class CRandom : public b::variate_generator<b::mt19937&,Dist> // notice the reference, we do not want to copy the engine { public: /** use for Dist: CRandomI Ci(min,max); uses uniform_int<int> - integral types CRandomR Cr(min,max); uses uniform_real<double> - floating point types for other ditributions or types, use: CRandom<distribution<optional type>> Cr(0--3 params, depending on distribution); for distributions and params, see: http://www.boost.org/doc/libs/1_39_0/libs/random/random-distributions.html */ // forwarding constructors explicit CRandom() : variate_generator<b::mt19937&,Dist>( Singleton<b::mt19937>::Instance(unsigned int(time(NULL))), Dist() ) { } template<class P> explicit CRandom(const P & p1) : variate_generator<b::mt19937&,Dist>( Singleton<b::mt19937>::Instance(unsigned int(time(NULL))), Dist(p1) ) { } template<class P1, class P2> explicit CRandom(const P1 & p1, const P2 & p2) : variate_generator<b::mt19937&,Dist>( Singleton<b::mt19937>::Instance(unsigned int(time(NULL))), Dist(p1, p2) ) { } template<class P1, class P2, class P3> explicit CRandom(const P1 & p1, const P2 & p2, const P3 & p3) : variate_generator<b::mt19937&,Dist>( Singleton<b::mt19937>::Instance(unsigned int(time(NULL))), Dist(p1, p2, p3) ) { } }; // end declaration // shorthand typedefs typedef CRandom<b::uniform_int<int>> CRandomI; // even int is default type , specify it in case it ever changes typedef CRandom<b::uniform_real<double>> CRandomR; // even double is default type, specify it in case it ever changes // boolean: class whose () operator returns a random true or false class CRandomB { public: CRandomB(void) : _Cr(CRandomR(0.,1.)) {} bool operator()() { return _Cr() <= .5; } private: CRandomR _Cr; };
AMDG Diederick C. Niehorster wrote:
My code has now become what is pasted below. It does the trick and allows for singletons with a parameterized constructor.
This leaves the question of whether a singleton library would be a useful addition to boost. I would be willing to code and write, though this would be a learning process for me.
A Singleton library was rejected a while back if I recall correctly. You can search the mailing list archives if you're interested. In Christ, Steven Watanabe
I'm not getting the "parameter" part. Where is such a parameter supposed to come from? If include in the program Singleton<b::mt19937>::Instance(1) and somewhere else in the program or in a different execution module Singleton<b::mt19937>::Instance(2) What is supposed to happen? Two singletons? If not which one? Robert Ramey Diederick C. Niehorster wrote:
Hi All,
My code has now become what is pasted below. It does the trick and allows for singletons with a parameterized constructor.
This leaves the question of whether a singleton library would be a useful addition to boost. I would be willing to code and write, though this would be a learning process for me.
Best, Diederick -----
singleton class: --- #pragma once
// Meyers singleton with support for constructors with 1 parameter
// http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton... // http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton... // http://www.devarticles.com/c/a/Cplusplus/The-Singleton-Pattern-Revisited/ // http://www.cplusplus.com/forum/beginner/1459/
template <class T> class Singleton { public: static T& Instance() { static T _instance; return _instance; } template<class P> static T& Instance(const P & p) { static T _instance(p); return _instance; } private: Singleton(); // ctor hidden ~Singleton(); // dtor hidden Singleton(Singleton const&); // copy ctor hidden Singleton& operator=(Singleton const&); // assign op hidden }; ---- Random number class with default engine: ---- #pragma once
// includes #include <boost/random.hpp> #include <time.h> #include <iostream> #include "Singleton.h"
// namespaces namespace s = std; namespace b = boost;
// declaration template<class Dist> class CRandom : public b::variate_generator<b::mt19937&,Dist> // notice the reference, we do not want to copy the engine { public: /** use for Dist: CRandomI Ci(min,max); uses uniform_int<int> - integral types CRandomR Cr(min,max); uses uniform_real<double> - floating point types
for other ditributions or types, use: CRandom<distribution<optional type>> Cr(0--3 params, depending on distribution); for distributions and params, see: http://www.boost.org/doc/libs/1_39_0/libs/random/random-distributions.html */
// forwarding constructors explicit CRandom() : variate_generator<b::mt19937&,Dist>( Singleton<b::mt19937>::Instance(unsigned int(time(NULL))), Dist() ) { } template<class P> explicit CRandom(const P & p1) : variate_generator<b::mt19937&,Dist>( Singleton<b::mt19937>::Instance(unsigned int(time(NULL))), Dist(p1) ) { } template<class P1, class P2> explicit CRandom(const P1 & p1, const P2 & p2) : variate_generator<b::mt19937&,Dist>( Singleton<b::mt19937>::Instance(unsigned int(time(NULL))), Dist(p1, p2) ) { } template<class P1, class P2, class P3> explicit CRandom(const P1 & p1, const P2 & p2, const P3 & p3) : variate_generator<b::mt19937&,Dist>( Singleton<b::mt19937>::Instance(unsigned int(time(NULL))), Dist(p1, p2, p3) ) { } }; // end declaration
// shorthand typedefs typedef CRandom<b::uniform_int<int>> CRandomI; // even int is default type , specify it in case it ever changes typedef CRandom<b::uniform_real<double>> CRandomR; // even double is default type, specify it in case it ever changes
// boolean: class whose () operator returns a random true or false class CRandomB { public: CRandomB(void) : _Cr(CRandomR(0.,1.)) {}
bool operator()() { return _Cr() <= .5; }
private: CRandomR _Cr; };
On 29 Jul 2009, at 04:47, Diederick C. Niehorster wrote:
My code has now become what is pasted below. It does the trick and allows for singletons with a parameterized constructor.
I still don't see what your CRandom class offers over creating a variate_generator and putting it in a boost::function, if you are not familiar with the function library you should look it up, it's brilliant. More importantly though, I'm not sure you are thinking about your problem in the right way. How do you want to use your random number generator code? What classes as misuse and what kind of misuses do you want to warn the user about? For me the most important issue was forgetting to seed the generator, so that's why mine is coded that way. I think it may be worth asking yourself some of these questions, see if they are important to you and think how you current implementation would deal with them. 1) Do I want random numbers to be generated before main() has been called, do I want the code to stop me from doing this accidently? 2) Will I ever want to create random variables (CRandom<> objects) before main has been called? 3) Will I ever want to use a random variable which doesn't use the singleton instance as it's source of randomness, do I still want such a random generator to plug in with the rest of my code in a unified way? 4) Will I ever be using the generator in a multithreaded environment? Do I need it to always supply the same numbers to the same thread? Finally, I would also be very careful with your Singleton class, because I think (although I haven't checked) that Instance(), Instance(unsigned int), and Instance(unsigned int(*)()) will all successfully instantiate and all return different instances. Thanks, Kevin Martin
Hi Kevin, others, Thanks jp, I will look into your code. I have the following requirements: 1) only one generator may exist (hence the singleton), it does not matter whether this generator is constructed at program start or first use. I do not forsee ever using another generator. 2) generator is seeded upon construction. Once seeded, for further calls to the generator instance providing a seed, that seed should be ignored/the generator should not be reseeded. This is what my code currently does 3) Right now, i do not forsee the need of generating random numbers before main has been called. However, I am interested in knowing what the problem would be in trying to use my class before main has been called, I have never dealt with such problems and would appreciate a kick in the right direction so I can learn something about it. 4) will not be used in multithreaded environment. If it ever would be, I would like all threads to use the same generator instance. Is that what will happen now? (I know I would then also have to worry about race conditions, but lets not get into that now). On Wed, Jul 29, 2009 at 3:17 PM, Kevin Martin<kev82@khn.org.uk> wrote:
On 29 Jul 2009, at 04:47, Diederick C. Niehorster wrote:
My code has now become what is pasted below. It does the trick and allows for singletons with a parameterized constructor.
I still don't see what your CRandom class offers over creating a variate_generator and putting it in a boost::function, if you are not familiar with the function library you should look it up, it's brilliant.
I have looked it up, thank you for the suggestion. I, however do not see the advantage of wrapping the generator. Also, how does your approach assure that the same engine is always used and that this enigine is never destructed once constructed before program end (i see you are using a shared pointer, I assume it would destruct the engine when all references went out of scope)? I now have a compact class that also ensures i cannot forget to seed my engine as that is done in the constructor.
Finally, I would also be very careful with your Singleton class, because I think (although I haven't checked) that Instance(), Instance(unsigned int), and Instance(unsigned int(*)()) will all successfully instantiate and all return different instances.
I just tested this, and Instance() and Instance(unsigned int) indeed return different objects (different memory address), so this is an issue. How do I get around this, I want only one instance of boost::mt19937 to be instantiated, no matter whether any argument or what type of argument is supplied to Instance(). Should i use a Gamma Singleton for that (if (!m_pInstance) m_pInstance=new T; return *m_pInstance;)? Thank you for your feedback! (code attached below for convenience) Best, Diederick ----- // includes #include <boost/random.hpp> #include <time.h> #include <iostream> namespace s = std; namespace b = boost; // Meyers singleton with support for constructors with 1 parameter // http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton... // http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton... // http://www.devarticles.com/c/a/Cplusplus/The-Singleton-Pattern-Revisited/ // http://www.cplusplus.com/forum/beginner/1459/ template <class T> class Singleton { public: static T& Instance() { static T _instance; return _instance; } template<class P> static T& Instance(const P & p) { static T _instance(p); return _instance; } private: Singleton(); // ctor hidden ~Singleton(); // dtor hidden Singleton(Singleton const&); // copy ctor hidden Singleton& operator=(Singleton const&); // assign op hidden }; // declaration template<class Dist> class CRandom : public b::variate_generator<b::mt19937&,Dist> // notice the reference, we do not want to copy the engine { public: /** use for Dist: CRandomI Ci(min,max); uses uniform_int<int> - integral types CRandomR Cr(min,max); uses uniform_real<double> - floating point types for other ditributions or types, use: CRandom<distribution<optional type>> Cr(0--3 params, depending on distribution); for distributions and params, see: http://www.boost.org/doc/libs/1_39_0/libs/random/random-distributions.html */ // forwarding constructors explicit CRandom() : variate_generator<b::mt19937&,Dist>( Singleton<b::mt19937>::Instance(/*unsigned int(time(NULL))*/), Dist() ) { s::cout << &Singleton<b::mt19937>::Instance() << s::endl; } template<class P> explicit CRandom(const P & p1) : variate_generator<b::mt19937&,Dist>( Singleton<b::mt19937>::Instance(unsigned int(time(NULL))), Dist(p1) ) { } template<class P1, class P2> explicit CRandom(const P1 & p1, const P2 & p2) : variate_generator<b::mt19937&,Dist>( Singleton<b::mt19937>::Instance(unsigned int(time(NULL))), Dist(p1, p2) ) { s::cout << &Singleton<b::mt19937>::Instance(unsigned int(time(NULL))) << s::endl; } template<class P1, class P2, class P3> explicit CRandom(const P1 & p1, const P2 & p2, const P3 & p3) : variate_generator<b::mt19937&,Dist>( Singleton<b::mt19937>::Instance(unsigned int(time(NULL))), Dist(p1, p2, p3) ) { } }; // end declaration // shorthand typedefs // random integer within range typedef CRandom<b::uniform_int<int>> CRandomI; // even int is default type , specify it in case it ever changes // random real number within range typedef CRandom<b::uniform_real<double>> CRandomR; // even double is default type, specify it in case it ever changes // random boolean typedef CRandom<b::bernoulli_distribution<double>> CRandomB; // even double is default type, specify it in case it ever changes //main int main(int argc, char* argv[]) { s::cout << "check 0" << s::endl; s::cout << "ctor 1" << s::endl; CRandomI Cr(1,10000); s::cout << "after ctor 1" << s::endl; int test = Cr(); s::cout << "random: " << test << s::endl; s::cout << "dtor 1" << s::endl; Cr.~CRandom(); s::cout << "ctor 2" << s::endl; CRandomI Cr2(1,10000); s::cout << "after ctor 2" << s::endl; int test2 = Cr2(); s::cout << "random: " << test2 << s::endl; CRandomB Cr3; // exit return 1; }
On Aug 4, 1:39 am, "Diederick C. Niehorster" <dcni...@gmail.com> wrote:
Hi Kevin, others, 2) generator is seeded upon construction. Once seeded, for further calls to the generator instance providing a seed, that seed should be ignored/the generator should not be reseeded. This is what my code currently does
The big question is whether you need the ability to set the seed when you construct it or can you stick with casting the time() or equivalent. As far as I can tell, most singleton libraries instantiate the object on the first use. If you need the ability to set the seed initially, you may need the ability to reseed.
3) Right now, i do not forsee the need of generating random numbers before main has been called. However, I am interested in knowing what the problem would be in trying to use my class before main has been called, I have never dealt with such problems and would appreciate a kick in the right direction so I can learn something about it.
I haven't had this problem, the singleton seems to create itself on first use.
4) will not be used in multithreaded environment. If it ever would be, I would like all threads to use the same generator instance. Is that what will happen now? (I know I would then also have to worry about race conditions, but lets not get into that now).
Right now there is no thread concurrency in my implementation. It is possible that the random number generators themselves are thread-safe, but who knows. If this isn't a problem, then you may be able to do this.
On Wed, Jul 29, 2009 at 3:17 PM, Kevin Martin<ke...@khn.org.uk> wrote:
I still don't see what your CRandom class offers over creating a variate_generator and putting it in a boost::function, if you are not familiar with the function library you should look it up, it's brilliant.
For me, the generator packages up a bunch of functionality, allows reseeding, and could be used with thread local storage once I figure that out. This is definitely a more complicated use case, so you might be right that it is overkill for this situation. Regardless, whether you have a boost::function or just the variate_generator, I am not sure how this helps the singleton problem. You can have a global variable that contains the variate generator, or the function object, but it still means either a singleton or a global. And you need to be careful with the ODR if you have multiple cpp files.
I have looked it up, thank you for the suggestion. I, however do not see the advantage of wrapping the generator. Also, how does your approach assure that the same engine is always used and that this enigine is never destructed once constructed before program end (i see you are using a shared pointer, I assume it would destruct the engine when all references went out of scope)? I now have a compact class that also ensures i cannot forget to seed my engine as that is done in the constructor.
The singleton libraries properly destruct on program exit, and if shared pointers are used, then the variates themselves will be destructed. If there is a chance that the singleton could be destroyed (or there are dependencies in singletons where destroying in the wrong order causes havoc), I know that Loki has phoenix singletons and other features I have never used.
On 4 Aug 2009, at 06:39, Diederick C. Niehorster wrote:
I have the following requirements:
1) only one generator may exist (hence the singleton), it does not matter whether this generator is constructed at program start or first use. I do not forsee ever using another generator.
Ok, I guess our requirements are very different. I don't understand why you would need to force there to only ever be one instance, certainly not to the extent where you go and write code to enforce it.
2) generator is seeded upon construction.
But where does this happen, with your design it is not always guaranteed to be in the same place.
Once seeded, for further calls to the generator instance providing a seed, that seed should be ignored/the generator should not be reseeded. This is what my code currently does
Is repeatability of experiments not an issue for you? If you want to repeat runs then you need to know what the seed value is before you start drawing numbers from the generator, and you also need to be able to set it before any numbers are drawn. At what point do you set the seed?
3) Right now, i do not forsee the need of generating random numbers before main has been called. However, I am interested in knowing what the problem would be in trying to use my class before main has been called, I have never dealt with such problems and would appreciate a kick in the right direction so I can learn something about it.
What I was trying to get at is that if you are intending to seed the generator with a specific value, then this can't really happen until main(). However if you have a global object whose constructor draws some numbers from the generator, then it will do so before the seed is set, this is clearly bad.
4) will not be used in multithreaded environment. If it ever would be, I would like all threads to use the same generator instance. Is that what will happen now? (I know I would then also have to worry about race conditions, but lets not get into that now).
The multithreaded problem is a real pain, the issue once again is repeatability. If thread A and B are both requesting a number, then there is no deterministic guarantee about which thread will manage to lock the appropriate mutex first, and so over multiple executions, the same threads will not get the same numbers.
I have looked it up, thank you for the suggestion. I, however do not see the advantage of wrapping the generator.
Well you are wrapping up the variate_generator yourself with your specializations of the CRandom template. My suggestion is that instead of your CRandom class, you just return the variate_generator inside a boost function.
Also, how does your approach assure that the same engine is always used and that this enigine is never destructed once constructed before program end
The shared_ptr is a static variable in an object file, it is only accessible by functions. The set function will only allow it to be set once. A reference to the generator is obtained by calling a global function and it will always return the same thing (assuming it has been allocated). Destruction will occur whenever the operating system destroys global objects. I have no idea when that is, and it is most likely very platform dependent, however it will always be long after main has returned.
(i see you are using a shared pointer, I assume it would destruct the engine when all references went out of scope)?
There should only ever be two shared_ptrs point to the generator, the first is the one that holds the instance I create, the second is the static global variable. Whenever I create a variate_generator, it does NOT pass any shared_ptrs around or alter any reference counts, it just passes the address of the actual generator. That's because I know the global variable will keep the generator in scope for all the time that I am in main() and thus the entre scope of the variate_generator.
I now have a compact class that also ensures i cannot forget to seed my engine as that is done in the constructor.
Does it make sure you can't forget to seed it, or does it automatically seed it with time(), there is a difference.
I just tested this, and Instance() and Instance(unsigned int) indeed return different objects (different memory address), so this is an issue. How do I get around this, I want only one instance of boost::mt19937 to be instantiated, no matter whether any argument or what type of argument is supplied to Instance(). Should i use a Gamma Singleton for that (if (!m_pInstance) m_pInstance=new T; return *m_pInstance;)?
Sorry, I don't know what a Gamma Singleton is, if you haven't gathered yet I'm a little anti-singleton. I think it's a far too overused, not particularly useful pattern. To solve this issue you need the object that is the focus of the singleton to only exist in one place. Off the top of my head I would suggest a static class variable which points to the object in question. Thanks, Kevin Martin
Hi Kevin, others, Thank you for your responses, sorry for the long delay. I have decided to try to do without the whole singleton (although I don't really see what the point is of avoiding a singleton if we still have a global pointer, its almost the same thing) as an exercise and try out Kevin's implementation. I made some small changes to the code (code at bottom fo post) to make sure that the generator is constructed if it wasn't yet (and seeded in the process) so i don't have to do that by hand in my code. That exactly fits what i need, and as it is seeded automatically, i cannot forget to do so. I would never want to change my seed, nor be able to set it to a specific value manually. On Wed, Aug 5, 2009 at 12:10 AM, Kevin Martin<kev82@khn.org.uk> wrote:
On 4 Aug 2009, at 06:39, Diederick C. Niehorster wrote:
I have looked it up, thank you for the suggestion. I, however do not see the advantage of wrapping the generator.
Well you are wrapping up the variate_generator yourself with your specializations of the CRandom template. My suggestion is that instead of your CRandom class, you just return the variate_generator inside a boost function.
Hmm, i have tried so, but the syntax to actually extract the random numbers becomes very complicated now (I think i am missing a point here, i am new to boost.function). With my class, i could simply create an instance of a variate generator and then get a random number using the () operator. See example: CRandom<boost::uniform_int<int>> Cr(1,100); int test = Cr(); which with a typedef "typedef CRandom<b::uniform_int<int>> CRandomI;" i can easily shorten to: CRandomI Cr(1,100); int test = Cr(); I have only managed to find two ways to get my random number using the boost.function approach, both of which need considerably more typeing by the user. It makes me want to wrap the boost.function in a class... (Method one is stupid of course, it would generate a new distribution every time i request a number.) What step am I still missing here? Thanks and best regards, Diederick ---- // includes #include <boost/random.hpp> #include <time.h> #include <iostream> #include <boost/shared_ptr.hpp> #include <boost/function.hpp> // could use a macro to set the generator used in the code, for easy change // kevin martin: static boost::shared_ptr<boost::mt19937> generator_; void grng_setGenerator(boost::shared_ptr<boost::mt19937> ptr) { if(!ptr) throw std::runtime_error("Tried to set generator to NULL pointer"); if(generator_) throw std::runtime_error("Tried to set generator more than once"); generator_ = ptr; } boost::mt19937 &grng_generator() { if(generator_) return *generator_; // if doesn't exist, set grng_setGenerator(boost::shared_ptr<boost::mt19937>(new boost::mt19937(unsigned int(time(NULL))))); if(generator_) return *generator_; // if still doesn't exist, error throw std::runtime_error("Requested RNG, but there isn't one"); } template<class Distribution_> boost::function<typename Distribution_::result_type ()> grng_randomVariable(const Distribution_ &d) { boost::variate_generator<boost::mt19937&, Distribution_> rv(grng_generator(), d); return boost::function<typename Distribution_::result_type ()>(rv); } //main int main(int argc, char* argv[]) { // 1 int a = grng_randomVariable(boost::uniform_int<int>(1,100))(); std::cout << a << std::endl; // 2 boost::function<int ()> Ci(grng_randomVariable(boost::uniform_int<int>(1,100))); std::cout << Ci() << std::endl; return 1; }
On 17 Aug 2009, at 04:51, Diederick C. Niehorster wrote:
I have decided to try to do without the whole singleton (although I don't really see what the point is of avoiding a singleton if we still have a global pointer, its almost the same thing) as an exercise and try out Kevin's implementation.
A singleton is extra code and extra work to maintain. Why create yourself more classes, more namespace pollution, and a more complex system when it is not necessary. I think I am just anti singleton. I believe it is far too overused, and apart from in a few niche cases provides nothing but additional complexity.
Hmm, i have tried so, but the syntax to actually extract the random numbers becomes very complicated now (I think i am missing a point here, i am new to boost.function).
Your method 2 is the one I use (except I use =) I wouldn't say it is a lot of typing, or particularly complicated, most editors will let you autocomplete the grng_function and the distribution name, so it's only about 15 keystrokes. In fact it is no different to CRandom<boost::uniform_int<int>> Cr(1,100); If you really wanted you could define a macro to make the function call for you, kind of equivalent to your typedef. I think that would make it harder to read though and not easier, as you would need a macro for each distribution. The reason I like it because I find it very readable and it only adds two symbols to the namespace. Take this code for example, if you had a separate wrapper class for the two distributions, would it be easier to read? (Note I use the old syntax for boost::function because I don't like the new one) boost::shared_ptr<boost::multi_array<int, 2> > vals = fbc_extractCellValues(board); MatrixSwap ms(*vals); boost::function0<bool> RVswapRow = grng_randomVariable( boost::bernoulli_distribution<>()); boost::function0<int> RVindex = grng_randomVariable( boost::uniform_smallint<>(0, board.boardSize()-1)); for(int i=0;i!=10000;++i) { int idx1 = 0, idx2 = 0; while(idx1 == idx2) { idx1 = RVindex(); idx2 = RVindex(); } if(RVswapRow()) { ms.swapRows(idx1, idx2); } else { ms.swapCols(idx1, idx2); } } Thanks, Kevin Martin
Kevin Martin wrote:
I think I am just anti singleton. I believe it is far too overused, and apart from in a few niche cases provides nothing but additional complexity. Singleton is victim of the same "danger of cool things" than OO in general. When discovering OO, people go like "yeah turn everything into objects!". When discoverign design pattern, people go like "yeah let' s use singleton for w/e object".
There is huge cons against use of singleton in general case. Using a static const object usually do the same without all the hassle. -- ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35
Thank Kevin, Agreed, syntax doesn't change much, but your implementation is more lightweight. It doesn't add only two symbols though, it adds: generator_ grng_setGenerator() grng_generator() grng_randomVariable() or do you put those in their own namespace? Thanks again, I've been enlightened. Best, Diederick On Mon, Aug 17, 2009 at 3:25 PM, Kevin Martin<kev82@khn.org.uk> wrote:
On 17 Aug 2009, at 04:51, Diederick C. Niehorster wrote:
I have decided to try to do without the whole singleton (although I don't really see what the point is of avoiding a singleton if we still have a global pointer, its almost the same thing) as an exercise and try out Kevin's implementation.
A singleton is extra code and extra work to maintain. Why create yourself more classes, more namespace pollution, and a more complex system when it is not necessary.
I think I am just anti singleton. I believe it is far too overused, and apart from in a few niche cases provides nothing but additional complexity.
Hmm, i have tried so, but the syntax to actually extract the random numbers becomes very complicated now (I think i am missing a point here, i am new to boost.function).
Your method 2 is the one I use (except I use =) I wouldn't say it is a lot of typing, or particularly complicated, most editors will let you autocomplete the grng_function and the distribution name, so it's only about 15 keystrokes. In fact it is no different to
CRandom<boost::uniform_int<int>> Cr(1,100);
If you really wanted you could define a macro to make the function call for you, kind of equivalent to your typedef. I think that would make it harder to read though and not easier, as you would need a macro for each distribution.
The reason I like it because I find it very readable and it only adds two symbols to the namespace. Take this code for example, if you had a separate wrapper class for the two distributions, would it be easier to read?
(Note I use the old syntax for boost::function because I don't like the new one)
boost::shared_ptr<boost::multi_array<int, 2> > vals = fbc_extractCellValues(board); MatrixSwap ms(*vals);
boost::function0<bool> RVswapRow = grng_randomVariable( boost::bernoulli_distribution<>()); boost::function0<int> RVindex = grng_randomVariable( boost::uniform_smallint<>(0, board.boardSize()-1));
for(int i=0;i!=10000;++i) { int idx1 = 0, idx2 = 0; while(idx1 == idx2) { idx1 = RVindex(); idx2 = RVindex(); } if(RVswapRow()) { ms.swapRows(idx1, idx2); } else { ms.swapCols(idx1, idx2); } }
Thanks, Kevin Martin _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On 17 Aug 2009, at 10:44, Diederick C. Niehorster wrote:
It doesn't add only two symbols though, it adds:
generator_
This should not be exported, in fact exporting this defeats the purpose of having generator and setGenerator. It should be in it's own compilation unit with static linkage and not in a header file visible to anything else.
grng_setGenerator()
This is one symbol
grng_generator()
This is another symbol
grng_randomVariable()
This is a template function and is recompiled in every compilation unit where it is used. I have never checked, but I always assumed that the compiler would inline it, so it shouldn't even be a function, never mind an exported symbol. However, you are right that it does add an extra name you can't use, I was thinking in terms of exported symbols.
or do you put those in their own namespace?
I've still not really got to grips with when to put things in namespaces and when not to. At the moment I only tend to use a namespace if I have a large collection of classes constituting a module. The grng_ prefix is kind of like a namespace to remind me what the functions are for because a global function setGenerator and generator are not very specific and likely to introduce collisions. I don't think it would cause any harm to put them in their own namespace though.
Thanks again, I've been enlightened.
Glad I could help Thanks, Kevin Martin
On Jul 28, 8:14 pm, "Diederick C. Niehorster" <dcni...@gmail.com> wrote:
Hi Kevin,
Thank you for your suggestions, I have learned from your code but don't think it is optimally suited for my needs. In general, wouldn't it be a good idea to have a singleton library inside boost? To my understanding they are used quite often, so better provide the world with a (few) good implementation(s suited for different needs). What do you think?
I ended up using the Loki singleton for the exact same purpose... though I am happy to change for a more flexible implementation. For those who are wondering the use case: When you have a library doing a great deal of montecarlo, you can't keep recreating the generators in sub-functions. For example, you want to be able to easily draw uniforms all over your library without passing around a generator every time from the library user code. Also, you sometimes need to start with the same seed value for regression testing across a variety of functions. Here is a link to my implementation (apologies for bad style and mistakes, I wrote a lot of it before people in this group started teaching me C++ and generic programming. And thanks again to everyone for your help over the last year). http://econtoolkit.com/browser/libraries/trunk/etk/etk/math/random/random.hp... This is also wrapping the Intel MKL VSL for streams of multivariate normals. See http://econtoolkit.com/browser/libraries/trunk/etk/etk/math/distributions/mu... for how that part of the singleton is used in the draw() function. The problem I have with my implementation is that what I really want is a thread-local singleton. If I have to make the access threadsafe, then I may be better off recreating it every time. Any ideas on how best to do this? Could it be done with the boost::serialization singleton? My guess is that it may be possible by using the loki creation policy, but I have no idea how to go about doing it.
jp wrote:
On Jul 28, 8:14 pm, "Diederick C. Niehorster" <dcni...@gmail.com> The problem I have with my implementation is that what I really want is a thread-local singleton. If I have to make the access threadsafe, then I may be better off recreating it every time. Any ideas on how best to do this? Could it be done with the boost::serialization singleton? My guess is that it may be possible by using the loki creation policy, but I have no idea how to go about doing it.
See for example http://www.boostcookbook.com/Recipe:/1235044 --> Mika Heiskanen
jp wrote: [snip]
The problem I have with my implementation is that what I really want is a thread-local singleton. If I have to make the access threadsafe, then I may be better off recreating it every time. Any ideas on how best to do this? Could it be done with the boost::serialization singleton? My guess is that it may be possible by using the loki creation policy, but I have no idea how to go about doing it.
Perhaps using http://tinyurl.com/m2pukz? I.e., something like below (untested)? Kind regards, Rutger template< typename Singleton > Singleton& get_singleton() { static boost::thread_specific_ptr< Singleton > m_singleton; if ( !m_singleton.get() ) { m_singleton.reset( new Singleton() ); } return *m_singleton; }
Dear Robert, Thanks! I will look into http://www.boost.org/doc/libs/1_39_0/libs/serialization/doc/singleton.html, I should not be reinventing the wheel ;) Dear Steven, Sharp eye, good point. Now two different numbers get generated and all those destructor calls dissapeared. It seems one too many dissapeared even (see program output below). Even though MSVC does not complain about memory leaks, at end of program the destructor never gets called. Lets see if Robert's singleton class solves this, otherwise i suppose i should look into using scoped_ptr? Thanks a lot for your replies, Diederick ------ output: check 0 00000000 ctor 1 after ctor 1 003462E0 random: 8148 dtor 1 ctor 2 after ctor 2 003462E0 random: 1355 Press any key to continue . . . On Sun, Jul 26, 2009 at 1:16 PM, Steven Watanabe<watanabesj@gmail.com> wrote:
AMDG
Diederick C. Niehorster wrote:
template<class Dist> class CRandom { public: <snip> private: boost::variate_generator<boost::mt19937,Dist> Gen; };
This copies the engine. Try boost::variate_generator<boost::mt19937&,Dist>
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Thanks Robert, Your singleton makes stuff really easy. For those interested, code below works like a breeze. Destructor is also called at program exit, so no leaks will occur. Best, Diederick --- #pragma once // includes #include <boost/random.hpp> #include <boost/serialization/singleton.hpp> #include <time.h> using namespace std; namespace bs = boost::serialization; // declaration template<class Dist> class CRandom { public: /** use for Dist: CRandomI Ci(min,max); uses uniform_int<int> - integral types CRandomR Cr(min,max); uses uniform_real<double> - floating point types for other ditributions or types, use: CRandom<distribution<optional type>> Cr(0--3 params, depending on distribution); for distributions and params, see: http://www.boost.org/doc/libs/1_39_0/libs/random/random-distributions.html engine is wrapped following singleton pattern, so every instantiation of CRandom uses the same engine. Singleton of boost::serialization used */ // forwarding constructors explicit CRandom() : Gen(bs::singleton<boost::mt19937>::get_mutable_instance(), Dist()) { } template<class P> explicit CRandom(const P & p1) : Gen(bs::singleton<boost::mt19937>::get_mutable_instance(), Dist(p1)) { } template<class P> explicit CRandom(const P & p1, const P & p2) : Gen(bs::singleton<boost::mt19937>::get_mutable_instance(), Dist(p1, p2)) { } template<class P> explicit CRandom(const P & p1, const P & p2, const P & p3) : Gen(bs::singleton<boost::mt19937>::get_mutable_instance(), Dist(p1, p2, p3)) { } ~CRandom(void) {}; typedef typename Dist::result_type result_type; result_type operator()() { return Gen(); } template<class T> result_type operator()(T value) { return Gen(value); } private: boost::variate_generator<boost::mt19937&,Dist> Gen; }; // end declaration // shorthand typedefs typedef CRandom<boost::uniform_int<int>> CRandomI; // even int is default type , specify it in case it ever changes typedef CRandom<boost::uniform_real<double>> CRandomR; // even double is default type, specify it in case it ever changes On Sun, Jul 26, 2009 at 1:54 PM, Diederick C. Niehorster<dcnieho@gmail.com> wrote:
Dear Robert, Thanks! I will look into http://www.boost.org/doc/libs/1_39_0/libs/serialization/doc/singleton.html, I should not be reinventing the wheel ;)
Dear Steven, Sharp eye, good point. Now two different numbers get generated and all those destructor calls dissapeared.
It seems one too many dissapeared even (see program output below). Even though MSVC does not complain about memory leaks, at end of program the destructor never gets called. Lets see if Robert's singleton class solves this, otherwise i suppose i should look into using scoped_ptr?
Thanks a lot for your replies, Diederick
------ output: check 0 00000000 ctor 1 after ctor 1 003462E0 random: 8148 dtor 1 ctor 2 after ctor 2 003462E0 random: 1355 Press any key to continue . . .
On Sun, Jul 26, 2009 at 1:16 PM, Steven Watanabe<watanabesj@gmail.com> wrote:
AMDG
Diederick C. Niehorster wrote:
template<class Dist> class CRandom { public: <snip> private: boost::variate_generator<boost::mt19937,Dist> Gen; };
This copies the engine. Try boost::variate_generator<boost::mt19937&,Dist>
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Maybe you want to try the one in the serialization library. Robert Ramey Diederick C. Niehorster wrote:
Hi All,
I have been writing a wrapper around the variate_generator as I always want to use the same number generator, but do want to use different distributions. As I want to use only one instance of the engine instance for all instanced of my random number generator class, I used a singleton pattern. as is my first time using it, I decided to test it generously, to try and see if the same instance of the enigine is used. So not only did i check if the engine pointer for different instances of my random class is the same, but i also checked if the destructor for the engine (does not) get called (i've added a constructor to the boost header file temporarily) and whether the random numbers generated are indeed not the same.
It seems my code does not work, the destructor gets called weirdly often, e.g., 4 times every time i initialize my random class. Also, the numbers generated by the two generators are the same, indicating the engine is reinitialized for every instance of my random class. Yet, the pointer to the engine is the same (note that it is also the same if i dont call the destructor in between).
I am using MSVC 2008 on windows XP 32 bit.
What am I doing wrong? As I am learning, any other feedback is also very welcome.
Best, Diederick ---- output of run of code below: check 0 00000000 ctor 1 destructor destructor destructor destructor after ctor 1 003462E0 random: 8148 dtor 1 destructor ctor 2 destructor destructor destructor destructor after ctor 2 003462E0 random: 8148 destructor destructor
---- code // includes #include <boost/random.hpp> #include <time.h> #include <iostream> using namespace std;
// declaration template<class Dist> class CRandom { public: /** use for Dist: CRandomI Ci(min,max); uses uniform_int<int> - integral types CRandomR Cr(min,max); uses uniform_real<double> - floating point types
for other ditributions or types, use: CRandom<distribution<optional type>> Cr(0--3 params, depending on distribution); for distributions and params, see: http://www.boost.org/doc/libs/1_39_0/libs/random/random-distributions.html */
// forwarding constructors explicit CRandom() : Gen(*EngineSingleton::Eng(), Dist()) { } template<class P> explicit CRandom(const P & p1) : Gen(*EngineSingleton::Eng(), Dist(p1)) { } template<class P> explicit CRandom(const P & p1, const P & p2) : Gen(*EngineSingleton::Eng(), Dist(p1, p2)) { } template<class P> explicit CRandom(const P & p1, const P & p2, const P & p3) : Gen(*EngineSingleton::Eng(), Dist(p1, p2, p3)) { }
~CRandom(void) {};
typedef typename Dist::result_type result_type;
result_type operator()() { return Gen(); } template<class T> result_type operator()(T value) { return Gen(value); }
private: boost::variate_generator<boost::mt19937,Dist> Gen; }; // end declaration
// shorthand typedefs typedef CRandom<boost::uniform_int<int>> CRandomI; // even int is default type , specify it in case it ever changes typedef CRandom<boost::uniform_real<double>> CRandomR; // even double is default type, specify it in case it ever changes
/** engine wrapper class following singleton pattern, so every instantiation of CRandom uses the same engine based on: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf */ // declaration class EngineSingleton { public: static boost::mt19937* Eng(); static boost::mt19937* GetEngPoint() {return pEng;}; // for test only protected: // disallow (copy) construction and assignment operator EngineSingleton(); EngineSingleton(const EngineSingleton&); EngineSingleton& operator=(const EngineSingleton&); private: static boost::mt19937* pEng; }; // end declaration
// implementation boost::mt19937* EngineSingleton::pEng = NULL;
boost::mt19937* EngineSingleton::Eng() { if (pEng == NULL) { pEng = new boost::mt19937(/*unsigned int(time(NULL))*/); // initialize with same seed always, for test only } return pEng; } // end implementation
//main int main(int argc, char* argv[]) { cout << "check 0" << endl; cout << EngineSingleton::GetEngPoint() << endl;
cout << "ctor 1" << endl; CRandomI Cr(1,10000); cout << "after ctor 1" << endl; cout << EngineSingleton::GetEngPoint() << endl; int test = Cr(); cout << "random: " << test << endl;
cout << "dtor 1" << endl; Cr.~CRandom();
cout << "ctor 2" << endl; CRandomI Cr2(1,10000); cout << "after ctor 2" << endl; cout << EngineSingleton::GetEngPoint() << endl; int test2 = Cr2(); cout << "random: " << test2 << endl;
// exit return 1; }
On 26 Jul 2009, at 03:44, Diederick C. Niehorster wrote:
I have been writing a wrapper around the variate_generator as I always want to use the same number generator, but do want to use different distributions.
I must admit I haven't read all your code in detail, so it may do more than I realise, but I had the same problem as this a while ago. My solution was a little simpler, I just use a static boost::shared_ptr to hold the singleton instance and for a given distribution I put the variate_generator into a boost::function. I like this approach because it will cause an exception if I try and use the generator before I've seeded it, and it will also complain if I accidently initialise it more than once. Thanks, Kevin Martin static boost::shared_ptr<boost::mt19937> generator_; boost::mt19937 &grng_generator() { if(generator_) return *generator_; throw std::runtime_error("Requrested RNG, but there isn't one"); } void grng_setGenerator(boost::shared_ptr<boost::mt19937> ptr) { if(!ptr) throw std::runtime_error("Tried to set generator to NULL pointer"); if(generator_) throw std::runtime_error("Tried to set generator more than once"); generator_ = ptr; } template<class Distribution_> boost::function0<typename Distribution_::result_type> grng_randomVariable(const Distribution_ &d) { boost::variate_generator<boost::mt19937&, Distribution_> rv( grng_generator(), d); return boost::function0<typename Distribution_::result_type>(rv); }
participants (10)
-
Boost lzw
-
Diederick C. Niehorster
-
Jesse Perla
-
joel
-
jp
-
Kevin Martin
-
Mika Heiskanen
-
Robert Ramey
-
Rutger ter Borg
-
Steven Watanabe