0%

how to implement singleton class in cpp

Intro

what singleton solve?

from stackoverflow here

Singletons solve one (and only one) problem.

Resource Contention.
If you have some resource that
(1) can only have a single instance, and
(2) you need to manage that single instance,
you need a singleton.

There aren’t many examples. A log file is the big one. You don’t want to just abandon a single log file. You want to flush, sync and close it properly. This is an example of a single shared resource that has to be managed.

It’s rare that you need a singleton. The reason they’re bad is that they feel like a global and they’re a fully paid up member of the GoF Design Patterns book.

When you think you need a global, you’re probably making a terrible design mistake.

local static object

Actually, in C++ preferred way is local static object.

singleton pure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Singleton
{
private:
Singleton();

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

static Singleton& instance()
{
static Singleton INSTANCE;
return INSTANCE;
}
};

singleton with shared_ptr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Singleton
{
private:
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;
}
};

singleton usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#define DISALLOW_COPY(TypeName) \
TypeName(const TypeName&)

#define DISALLOW_ASSIGN(TypeName) \
TypeName& operator=(const TypeName&)

#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
TypeName& operator=(const TypeName&)

class CSingleton
{
public:
static CSingleton &GetInstance()
{
static CSingleton instance;
return instance;
}
void DoSomething()
{
printf("void CSingleton::DoSomething() called.\n");
}

private:
CSingleton() {};
DISALLOW_COPY_AND_ASSIGN(CSingleton);
};

// usage
CSingleton::GetInstance().DoSomething(); // OK

CSingleton& singleton = CSingleton::GetInstance(); // OK with reference
singleton.DoSomething();

CSingleton singleton = CSingleton::GetInstance(); // ERROR (copy constructor)

Example

config.h

1
2
3
4
5
6
7
8
9
10
11
12
13
#pragma once

class Config
{
public:
static Config& GetInstance(std::string filename="./config.ini");
~Config();

private:
Config(std::string filename);
Config(const Config& ref) {}
Config& operator =(const Config& ref) { return *this; }
};

config.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "Config.h"

/*
static config instance will only be created once by calling Config::Config,
when program exit,static variable will be destoryed by calling Config::~Config.
*/

Config& Config::GetInstance(std::string filename)
{
static Config instance(filename);
return instance;
}

Config::Config(std::string filename)
{
std::cout << "[LOG] Config::Config count= "<<count << std::endl;
// load config from filename
// ...
}

Config::~Config()
{
std::cout << "[LOG] Config::~Config count= " << count << std::endl;
}

mysqldb.cpp

1
2
3
4
5
6
7
8
void MysqlDb::load_config(std::string filename)
{
this->mysql_connection = Config::GetInstance(filename).MYSQL_CONNECTION;
this->mysql_username = Config::GetInstance(filename).MYSQL_USERNAME;
this->mysql_password = Config::GetInstance(filename).MYSQL_PASSWORD;
this->mysql_database = Config::GetInstance(filename).MYSQL_DATABASE;
this->max_connection_pool_size = Config::GetInstance(filename).MAX_CONNECTION_POOL_SIZE;
}

Reference

History

  • 20180122: created.