Boost logo

Boost Users :

Subject: [Boost-users] shared_ptr singleton
From: Alessandro Re (akirosspower_at_[hidden])
Date: 2008-10-16 15:08:01


Hello,
I'm getting some troubles with shared_ptr when trying to implement a
singleton pattern.
Actually, it's not the singleton itself (which seems to work, in a
separate program), but in the context I need it, doesn't work.

I tried to figure out why (and actually I found an alternative
implementation which works), but still I'm trying to understand what
goes wrong.

I'm trying to do this:
having a hierarchy of classes where there is one Base class and a
number of derived ones, each class is in a different cpp file.
All these classes must be registered in a Register class, which is
itself derived from Object.
Register is the singleton, implemented like this:

class Register;
typedef shared_ptr<Register> RegisterP;
class Register: public Object {
public:
        Register();
        void add(string name) {
                // Stuff with name
        }
        static RegisterP global() {
                if (!_global) _global = RegisterP(new Register); // *
                return _global;
        }
private:
        static RegisterP _global;
};

To register the various classes, does exist a special class, not in
hierarchy, like this:

class ClassRegisterer {
public:
        ClassRegisterer::ClassRegisterer(string name) {
                Register::global()->register(name);
                // **
        }
}

#define REGISTER(C) ClassRegisterer _registerClass_ ## C ( #C)

In each file of the of the project, this macro is used when a class is created:

Foo.cpp
class Foo: public Object {...};
REGISTER(Foo);

Bar.cpp
class Bar: public Object {...};
REGISTER(Bar);

This is also used for the Register class itself:

Register.cpp
class Register: public Object {...};
REGISTER(Register);

The problem is that global() is called N times, but the new Register
(*) is executed twice, instead of once.
Investigating with some couts, I found out that - dunno why - the
pointer _global is set to 0 after the first execution,
in fact at the time of second execution it's created another object,
which isn't deleted and is kept.

Trying quickly with a debugger, it seems that at (**) a destructor for
shared_ptr is called,
and I think that it may be the cause of the issue, but I'm having an
hard time figuring this out and *why* a destructor is called (maybe
it's just for a temporary object).

Looking at boost docs, i found out this:
http://www.boost.org/doc/libs/1_35_0/libs/smart_ptr/sp_techniques.html#static
so I tried to use that null deleter, like this:

struct nullDeleter {
        void operator()(void const *p) const {
                cout << "Trying to delete " << p << endl;
        }
};

and used like:
                if (!_global) _global = RegisterP(new Register, nullDeleter());

The problem is that this is never called! The object is never
destroyed by this, but somehow the static _global is set to 0 (only
once), and thus allocated twice.

I temporary solved this using a static raw pointer, which is allocated
once and a shared_ptr is built with it:

class Register {
...
        static RegisterP global() {
                if (!_global) _global = new Register;
                return RegisterP(_global, nullDeleter());
        }
...
        static Register *_global;
};

Which works.

Any suggestion is welcome :)

Thanks

-- 
~Ale

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