Singleton Design Pattern - два способа

Все о программировании под *nix
Аватара пользователя
exe
Неотъемлемая часть форума
Сообщения: 860
Зарегистрирован: 28 ноя 2003, 21:08
Откуда: Минск

Singleton Design Pattern - два способа

Сообщение exe »

Люди кто-нибудь понимает следующее:


Singleton is probably the most widely used design pattern. Its intent is to ensure that a
class has only one instance, and to provide a global point of access to it. There are many
situations in which a singleton object is necessary: a GUI application must have a single
mouse, an active modem needs one and only one telephone line, an operating system can only
have one window manager, and a PC is connected to a single keyboard. I will show how to
implement the singleton pattern in C++ and explain how you can optimize its design for
single-threaded applications.

Design Considerations

Using a global object ensures that the instance is easily accessible but it doesn't keep you
from instantiating multiple objects—you can still create a local instance of the same class in
addition to the global one. The Singleton pattern provides an elegant solution to this problem
by making the class itself responsible for managing its sole instance. The sole instance is an
ordinary object of its class, but that class is written so that only one instance can ever be
created. This way, you guarantee that no other instance can be created. Furthermore, you
provide a global point of access to that instance. The Singleton class hides the operation that
creates the instance behind a static member function. This member function, traditionally
called Instance(), returns a pointer to the sole instance. Here's a declaration of such a class:


class Singleton
{
public:
static Singleton* Instance();
protected:
Singleton();
Singleton(const Singleton&);
Singleton& operator= (const Singleton&);
private:
static Singleton* pinstance;
};

Instead of Singleton, you can name your class Mouse, FileManager, Scheduler, etc., and
declare additional members accordingly. To ensure that users can't create local instances of
the class, Singleton's constructor, assignment operator, and copy constructor are declared
protected. The class also declares a private static pointer to its instance, pinstance. When the
static function Instance() is called for the first time, it creates the sole instance, assigns its
address to pinstance, and returns that address. In every subsequent invocation, Instance()
will merely return that address.

The class's implementation looks like this:

Singleton* Singleton::pinstance = 0;// initialize pointer
Singleton* Singleton::Instance ()
{
if (pinstance == 0) // is it the first call?
{
pinstance = new Singleton; // create sole instance
}
return pinstance; // address of sole instance
}
Singleton::Singleton()
{
//... perform necessary instance initializations
}

Users access the sole instance through the Instance() member function exclusively. Any
attempt to create an instance not through this function will fail because the class's
constructor is protected. Instance() uses lazy initialization. This means the value it returns is
created when the function is accessed for the first time. Note that this design is
bullet-proof—all the following Instance() calls return a pointer to the same instance:

Singleton *p1 = Singleton::Instance();
Singleton *p2 = p1->Instance();
Singleton & ref = * Singleton::Instance();

Although our example uses a single instance, with minor modifications to the function
Instance(), this design pattern permits a variable number of instances. For example, you can
design a class that allows up to five instances.

Optimizing Singleton for Single-Threaded Applications
Singleton allocates its sole instance on the free-store using operator new. Because operator
new is thread-safe, you can use this design pattern in multi-threaded applications. However,
there's a fly in the ointment: you must destroy the instance manually by calling delete before
the application terminates. Otherwise, not only are you causing a memory leak, but you also
bring about undefined behavior because Singleton's destructor will never get called.
Single-threaded applications can easily avoid this hassle by using a local static instance
instead of a dynamically allocated one. Here's a slightly different implementation of Instance()
that's suitable for single-threaded applications:

Singleton&Singleton::Instance ()
{
static Singleton inst;
return &inst;
}

The local static object inst is constructed when Instance() is called for the first time and
remains alive until the application terminates. Note that the pointer pinstance is now
redundant and can be removed from the class's declaration. Unlike dynamically allocated
objects, static objects are destroyed automatically when the application terminates, so you
shouldn't destroy the instance manually.



Почему второй способ через референс считается не thread-safe. Ну скока не
смотрю, не врубаюсь. Первый же то же не сахар:

Код: Выделить всё

 if (pinstance == 0)  // is it the first call?
{  
      [color=red]// Не thread-safe[/color]
      pinstance = new Singleton; // create sole instance
}
[