Boost logo

Boost Users :

Subject: Re: [Boost-users] [random] Singleton engine
From: Diederick C. Niehorster (dcnieho_at_[hidden])
Date: 2009-08-04 01:39:30


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_at_[hidden]> 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-Pattern-Part-I/
// http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton-Pattern-Part-2/
// 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;
}


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