Singleton mode of design mode

Write a singleton mode

Singleton pattern: as the name suggests, this class can only create one object.

Let the user call your method to create an object instead of creating an object through the method of class name.

class Singleton {
public:
	~Singleton() {
		cout << "Singleton() destruct" << endl;
	}
	Singleton* CreateObject() {
		return new Singleton();
	}
private:
	Singleton() {
		cout << "Singleton() construct" << endl;
	}
};

Call a function to return a pointer to an object, but the problem is that this function needs an object to call, but it can only create an object through this method, so it cannot be executed.

After static is added to this function, it becomes a static function and no object is required.

Retest

class Singleton {
public:
	~Singleton() {
		cout << "Singleton() destruct" << endl;
	}
	static Singleton* CreateObject() {
		return new Singleton();
	}
private:
	Singleton() {
		cout << "Singleton() construct" << endl;
	}
};
int main(int argc, char** argv) {
	Singleton* s1 = Singleton::CreateObject();
	Singleton* s2 = Singleton::CreateObject();
	return 0;
}

It is found that new will be called every time, and the new object address will be returned. We only need one object.

Then we create a new static pointer variable, and let the initial value of the pointer be nullptr; Then, if the object has not been created, give him new an address and assign it to this variable; If it has been created before, you can return directly.

class Singleton {
public:
	~Singleton() {
		cout << "Singleton() destruct" << endl;
	}
	static Singleton* CreateObject() {
		if (m_pObject == nullptr) {
			m_pObject = new Singleton();
		}
		return m_pObject;
	}
private:
	Singleton() {
		cout << "Singleton() construct" << endl;
	}
	static Singleton* m_pObject;
};
Singleton* Singleton::m_pObject = nullptr;
int main(int argc, char** argv) {
	Singleton* s1 = Singleton::CreateObject();
	Singleton* s2 = Singleton::CreateObject();
	return 0;
}

This is lazy. At the same time, a major problem is that there is a memory leak and the destructor of the class will not be called.

In the main function, you need to manually release the object pointer after using it up.

And it is still in the thread safety problem.

So what should I write

In the function, create a static object and return its address.

class Singleton {
public:
	~Singleton() {
		cout << "Singleton() destruct" << endl;
	}
	static Singleton* CreateObject() {
		static Singleton obj;
		return &obj;
	}
private:
	Singleton() {
		cout << "Singleton() construct" << endl;
	}
	static Singleton* m_pObject;
};
Singleton* Singleton::m_pObject = nullptr;
int main(int argc, char** argv) {
	Singleton* s1 = Singleton::CreateObject();
	Singleton* s2 = Singleton::CreateObject();
	return 0;
}

However, there is still a problem with using the pointer. If the user delete s the pointer in the main function, an error will occur. Because this object is not built in the heap.

So what should we do?

Instead of returning a pointer, it returns a reference.

class Singleton {
public:
	~Singleton() {
		cout << "Singleton() destruct" << endl;
	}
	static Singleton& CreateObject() {
		static Singleton obj;
		return obj;
	}
private:
	Singleton() {
		cout << "Singleton() construct" << endl;
	}
	static Singleton* m_pObject;
};
Singleton* Singleton::m_pObject = nullptr;
int main(int argc, char** argv) {
	Singleton& s1 = Singleton::CreateObject();
	Singleton& s2 = Singleton::CreateObject();
	return 0;
}

The program is modified as follows

After adding monitoring, the values are consistent.

However, if the type returned in the main function is not a reference type at this time, there is a process of copying the structure, and the reference is assigned to other objects.

Singleton s2 = Singleton::CreateObject();

Note you also need to limit the assignment constructor.

You can make the copy constructor of a class private. Is to add a copy constructor to the private property

	Singleton(Singleton& obj) {
		cout << "Singleton(Singleton& obj) construct" << endl;
	}

At this time, the above method with assignment structure cannot be compiled.

Another way is to disable copy construction without using private methods. Use the = delete method

//Singleton - only one instance
class Singleton {
public:
	~Singleton() {
		cout << "Singleton() destruct" << endl;
	}
	static Singleton& CreateObject() {
		static Singleton obj;
		return obj;
	}
	//Copy constructs are not allowed
	Singleton(Singleton& obj) = delete;
	//Default assignment operator overload
	Singleton* operator=(Singleton& obj) = delete;
private:
	Singleton() {
		cout << "Singleton() construct" << endl;
	}
};
int main(int argc, char** argv) {
	Singleton& s1=Singleton::CreateObject();
	return 0;
}

The log class can use the singleton mode. There is only one log instance. This function can be called anywhere in the program to create the log object to write the log.

Tags: Design Pattern Singleton pattern

Posted on Mon, 13 Sep 2021 16:40:42 -0400 by terje-s