Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CPlusPlusNotesForProfessionals.pdf
Скачиваний:
47
Добавлен:
20.05.2023
Размер:
5.11 Mб
Скачать

Chapter 113: Singleton Design Pattern

Section 113.1: Lazy Initialization

This example has been lifted from the Q & A section here:http://stackoverflow.com/a/1008289/3807729

See this article for a simple design for a lazy evaluated with guaranteed destruction singleton: Can any one provide me a sample of Singleton in c++?

The classic lazy evaluated and correctly destroyed singleton.

class S

{

public:

static S& getInstance()

{

static S instance; // Guaranteed to be destroyed. // Instantiated on first use.

return instance;

 

}

 

private:

 

S() {};

// Constructor? (the {} brackets) are needed here.

//C++ 03

//========

//Don't forget to declare these two. You want to make sure they

//are unacceptable otherwise you may accidentally get copies of

//your singleton appearing.

S(S const&);

//

Don't

Implement

void operator=(S const&); //

Don't

implement

//C++ 11

//=======

//We can use the better technique of deleting the methods

//we don't want.

public:

 

 

S(S

const&)

= delete;

void operator=(S const&)

= delete;

//Note: Scott Meyers mentions in his Effective Modern

//C++ book, that deleted functions should generally

//be public as it results in better error messages

//due to the compilers behavior to check accessibility

//before deleted status

};

See this article about when to use a singleton: (not often)

Singleton: How should it be used

See this two article about initialization order and how to cope:

Static variables initialisation order

Finding C++ static initialization order problems

See this article describing lifetimes:

What is the lifetime of a static variable in a C++ function?

See this article that discusses some threading implications to singletons:

Singleton instance declared as static variable of GetInstance method

GoalKicker.com – C++ Notes for Professionals

572

See this article that explains why double checked locking will not work on C++:

What are all the common undefined behaviours that a C++ programmer should know about?

Section 113.2: Static deinitialization-safe singleton

There are times with multiple static objects where you need to be able to guarantee that the singleton will not be destroyed until all the static objects that use the singleton no longer need it.

In this case std::shared_ptr can be used to keep the singleton alive for all users even when the static destructors are being called at the end of the program:

class Singleton

{

public:

Singleton(Singleton const&) = delete; Singleton& operator=(Singleton const&) = delete;

static std::shared_ptr<Singleton> instance()

{

static std::shared_ptr<Singleton> s{new Singleton}; return s;

}

private: Singleton() {}

};

NOTE: This example appears as an answer in the Q&A section here.

Section 113.3: Thread-safe Singeton

Version ≥ C++11

The C++11 standards guarantees that the initialization of function scope objects are initialized in a synchronized manner. This can be used to implement a thread-safe singleton with lazy initialization.

class Foo

{

public:

static Foo& instance()

{

static Foo inst; return inst;

}

private: Foo() {}

Foo(const Foo&) = delete;

Foo& operator =(const Foo&) = delete;

};

Section 113.4: Subclasses

class API

{

public:

static API& instance();

virtual ~API() {}

GoalKicker.com – C++ Notes for Professionals

573

virtual const char* func1() = 0; virtual void func2() = 0;

protected: API() {}

API(const API&) = delete;

API& operator=(const API&) = delete;

};

class WindowsAPI : public API

{

public:

virtual const char* func1() override { /* Windows code */ } virtual void func2() override { /* Windows code */ }

};

class LinuxAPI : public API

{

public:

virtual const char* func1() override { /* Linux code */ } virtual void func2() override { /* Linux code */ }

};

API& API::instance() { #if PLATFORM == WIN32

static WindowsAPI instance; #elif PLATFORM = LINUX

static LinuxAPI instance; #endif

return instance;

}

In this example, a simple compiler switch binds the API class to the appropriate subclass. In this way, API can be accessed without being coupled to platform-specific code.

GoalKicker.com – C++ Notes for Professionals

574