[C + + from bronze to king] Chapter 27: special design

Catalogue of series articles

preface

Master the design methods of common special classes.

1, Please design a class that can only create objects on the heap

  • Implementation method:
  • Declare the constructor of the class private and the copy constructor private. Prevent others from calling copy to generate objects on the stack.
  • A static member function is provided to complete the creation of heap objects in the static member function.
#define _CRT_SECURE_NO_WARNINGS   1
#include<iostream>
#include<memory>
using namespace std;

class HeapOnly
{
public:
	static HeapOnly* GetObj()
	{
		return new HeapOnly;
	}
private:
	HeapOnly()
	{}
	//C++98 declared private
	HeapOnly(HeapOnly&);
	
	//C++11
	HeapOnly(HeapOnly&) = delete;
};
int main()
{
	//HeapOnly* p = HeapOnly::GetObj();  To prevent memory leakage, use smart pointers
	std::shared_ptr<HeapOnly> sp1(HeapOnly::GetObj());
	return 0;
}

2, Please design a class that can only create objects on the stack

  • Method 1: privatize the constructor, and then design a static method to create an object to return.
  • Method 2: Mask new, because new calls void* operator new(size_t size) function at the bottom layer. Just mask the function. Note: also prevent positioning new.
#define _CRT_SECURE_NO_WARNINGS   1
#include<iostream>
using namespace std;

class StackOnly
{
public:
	static StackOnly GetObj()
	{
		return StackOnly();
	}
private:
	StackOnly(){}

	void* operator new(size_t size) = delete;
};
int main()
{
	StackOnly p = StackOnly::GetObj();
	//StackOnly* p = new StackOnly;
	return 0;
}

3, Please design a class that cannot be copied

  • Copying will only be released in two scenarios: copy constructor and assignment operator overloading. Therefore, if you want a class to prohibit copying, just make the class unable to call copy constructor and assignment operator overloading.
  • C++98: overload the copy constructor and assignment operator, only declare that they are not defined, and set their access rights to private.
  • reason:
  • Set to private: if you only declare that it is not set to private, you can't prohibit copying if you define it outside the class.
  • Only declare but not define: it is not defined because the function will not be called at all. In fact, it is meaningless to define it. It is simple not to write it. Moreover, if it is defined, it will not prevent internal copying of member functions.
  • C++11: extend the usage of delete. In addition to releasing the resources requested by new, if = delete is followed by the default member function, it means that the compiler will delete the default member function.
#define _CRT_SECURE_NO_WARNINGS   1
#include<iostream>
using namespace std;

class CopyBan
{
public:
	CopyBan()
	{}
private:
	//Only declared, undefined, and set private
	CopyBan(const CopyBan&);
	CopyBan operator=(const CopyBan&);

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

};
int main()
{
	CopyBan a;
	CopyBan b(a);
	CopyBan c;
	c = a;
	return 0;
}

4, Please design a class that cannot be inherited

The constructor is privatized in C++98:, and the constructor of the base class is not derived from the derived class. Cannot inherit.
C++11: Method final keyword, which modifies a class, indicating that the class cannot be inherited.

#define _CRT_SECURE_NO_WARNINGS   1
#include<iostream>
using namespace std;

class NoInherit final
{
public:
	static NoInherit GetInstance()
	{
		return NoInherit();
	}
private:
	NoInherit()
	{}
};
int main()
{
	NoInherit a = NoInherit::GetInstance();
	return 0;
}

5, Please design a class. Only one object can be created (singleton mode)


Design mode:

Design Pattern is a set of code design experience that is repeatedly used, known by most people, classified and summarized. Why do design patterns come into being? Just like the development of human history will produce the art of war. In the beginning, when there were wars between tribes, people fought against each other. Later, during the spring and Autumn period and the Warring States period, there were often wars between the seven countries. It was found that there was a routine in fighting. Later, Sun Tzu summarized Sun Tzu's art of war. Sun Tzu's art of war is similar.

Singleton mode:

A class can only create one object, that is, singleton mode, which can ensure that there is only one instance of the class in the system and provide a global access point to access it. The instance is shared by all program modules. For example, in a server program, the configuration information of the server is stored in a file. These configuration data are uniformly read by a singleton object, and then other objects in the service process obtain these configuration information through this singleton object. This way simplifies the configuration management in a complex environment.

#define _CRT_SECURE_NO_WARNINGS   1
#include<iostream>

#include<thread>
#include<vector>
#include<Windows.h>
using namespace std;

class Singleton
{
public:
	static Singleton* GetInstance()
	{
		Sleep(1000);
		if (_pinst == nullptr)
		{
			_pinst = new Singleton;
		}
		return _pinst;
	}
private:
	Singleton()
	{}
	Singleton(const Singleton&);
	Singleton& operator=(const Singleton&);
	static Singleton* _pinst;
};
Singleton* Singleton::_pinst = nullptr;

int main()
{
	//cout << Singleton::GetInstance() << endl;
	//cout << Singleton::GetInstance() << endl;
	//cout << Singleton::GetInstance() << endl;

	//Thread safety issues exist
	//Singleton copy(*Singleton::GetInstance());

	vector<std::thread> vthread;

	int n = 10;
	for (int i = 0; i < n; i++)
	{
		vthread.push_back(thread([]()
		{
			//cout << this_thread::get_id() << ":";
			cout << Singleton::GetInstance() << endl;
		}));
	}

	for (auto& t : vthread)
	{
		t.join();
	}

	return 0;
}

1. Hungry Han mode of single case mode

  • Hungry man model
  • That is, whether you use it or not in the future, a unique instance object will be created when the program starts.
Hungry man model
 Advantages: simple
 Disadvantages: it may cause the process to start slowly, and if there are multiple singleton object instances, the start order is uncertain
#define _CRT_SECURE_NO_WARNINGS   1

#include<iostream>
#include<vector>
#include<thread>
using namespace std;

namespace yyw
{
	//Hungry man mode -- create objects at the beginning (before the main function)
	class Singleton
	{
	public:
		static Singleton* GetInstance()
		{
			return &_inst;
		}

		Singleton(const Singleton&) = delete;
		Singleton& operator=(const Singleton&) = delete;
	private:
		Singleton()
		{}
		static Singleton _inst;
	};

	Singleton Singleton::_inst;
	//The static object was created before the main function. There is only the main thread, so there is no thread safety problem
	int x()
	{
		//cout << Singleton::GetInstance() << endl;
		//cout << Singleton::GetInstance() << endl;
		//cout << Singleton::GetInstance() << endl;

		//Thread safety issues exist
		//Singleton copy(*Singleton::GetInstance());

		vector<std::thread> vthread;

		int n = 10;
		for (int i = 0; i < n; i++)
		{
			vthread.push_back(thread([]()
			{
				//cout << this_thread::get_id() << ":";
				cout << Singleton::GetInstance() << endl;
			}));
		}

		for (auto& t : vthread)
		{
			t.join();
		}
		return 0;
	}
}
int main()
{
	yyw::x();
	return 0;
}

2. Lazy mode of singleton mode

  • Lazy mode
  • If the construction of a singleton object is very time-consuming or takes up a lot of resources, such as loading plug-ins, initializing network connections, reading files, etc., and the object may not be used when the program runs, it should also be initialized at the beginning of the program, which will lead to very slow program startup. So it's better to use lazy mode (delayed loading) in this case.
Lazy man
 Advantage: when you first use an instance object, you create it. The process starts without load. The startup sequence of multiple single instance instances is freely controlled.
Disadvantages: complex
#define _CRT_SECURE_NO_WARNINGS   1
#include<iostream>

#include<thread>
#include<vector>
#include<Windows.h>
#include<mutex>
using namespace std;
namespace Lazy_MAN
{

	//Lazy mode
	class Singleton
	{
	public:
		static Singleton* GetInstance()
		{
			Sleep(1000);   //Thread insecurity occurs when adding a lock or not



			//Local domain control unlocking timing

			//Double check locking mode,
			if (_pinst == nullptr)            //The first judgment is to prevent locking every time after the object is created, which is wasted.
			{
				//_mtx.lock();
				unique_lock<mutex> lock(_mtx);
				if (_pinst == nullptr)      //The second judgment is to prevent multiple threads from writing unsafe together
				{
					_pinst = new Singleton;
				}
				//_mtx.unlock();
			}

			return _pinst;
		}

		static void DelInstance()
		{
			//unique_lock<mutex> lock(_mtx);
			delete _pinst;
			_pinst = nullptr;
		}
	private:
		Singleton()
		{}
		Singleton(const Singleton&);
		Singleton& operator=(const Singleton&);

		static Singleton* _pinst;

		static mutex _mtx;
	};

	//1. If you want to release the singleton object manually, you can call DelInstance
	//2. If you need to release objects normally at the end of the program, you can add the following objects
	class GC
	{
	public:
		~GC()
		{
			Singleton::DelInstance();
		}
	};

	//Define a static member variable. When the program ends, the system will automatically call its destructor to release the singleton object.
	static GC gc;

	Singleton* Singleton::_pinst = nullptr;
	mutex Singleton::_mtx;

	int main()
	{
		//cout << Singleton::GetInstance() << endl;
		//cout << Singleton::GetInstance() << endl;
		//cout << Singleton::GetInstance() << endl;

		//Thread safety issues exist
		//Singleton copy(*Singleton::GetInstance());

		vector<std::thread> vthread;

		int n = 10;
		for (int i = 0; i < n; i++)
		{
			vthread.push_back(thread([]()
			{
				//cout << this_thread::get_id() << ":";
				cout << Singleton::GetInstance() << endl;
			}));
		}

		for (auto& t : vthread)
		{
			t.join();
		}

		return 0;
	}
}

summary

The above is what we want to talk about today. This paper introduces some special class design and single case mode. Special classes often appear in interviews. We must master them. In addition, if there are any problems above, please understand my brother's advice, but it doesn't matter. It's mainly because I can insist. I hope some students who study together can help me correct them. However, if you can be gentle, please tell me that love and peace are the eternal theme and love you.

Tags: C++ Design Pattern

Posted on Tue, 05 Oct 2021 19:24:35 -0400 by logging