Boost logo

Boost Users :

Subject: [Boost-users] [random] Singleton engine
From: Diederick C. Niehorster (dcnieho_at_[hidden])
Date: 2009-07-25 22:44:50


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 list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net