Cuando NONCOPYABLE se encuentra con SINGLETON

Al implementar una clase singleton, generalmente es necesario establecer los permisos de acceso de varias funciones relacionadas con la construcción como privados o protegidos (preferiblemente privados). Pero suponga que hay docenas de clases singleton en un sistema a gran escala (esto es normal, las clases singleton son en realidad uno de los diseños de patrones de apariencia más comúnmente usados), y escribir cada una de ellas de esta manera es engorroso. Para reutilizar el código representado por estas operaciones, puede usar el arma proporcionada por la herencia del lenguaje C ++.

Diseñe la siguiente clase base:

1 class NonCopyable {
2 public:
3     NonCopyable() = default;
4     NonCopyable(const NonCopyable&) = delete;
5     void operator=(const NonCopyable& c) = delete;
6 };

Cuando la clase singleton hereda esta clase, el cliente no puede copiar o asignar el objeto instanciado de esta clase singleton, por lo que solo hay un objeto global en toda la memoria. La implementación de la clase NonCopyable aquí se refiere a boost :: noncopiable .

Después de resolver el problema de los permisos de acceso al constructor, hay otra pregunta, es decir, ¿cómo crear una instancia? La forma clásica de implementar una clase singleton es declarar un puntero a un objeto de clase estático privado en la clase, usar el método get para devolver una referencia a esta instancia de objeto y luego llamar a otros métodos de la clase a través de esta referencia. Muy bien, pero sigue siendo complicado implementar esto para cada clase singleton. En este momento, puede utilizar otra herramienta de reutilización de código proporcionada por C ++ - template. Primero implemente una clase de plantilla singleton general, y el parámetro de tipo de plantilla se pasa en el nombre de la clase singleton que se implementará, de modo que la construcción de la clase singleton (instanciación de plantilla) se complete en la fase de compilación.

La clase de plantilla general singleton se implementa de la siguiente manera:

Copiar codigo

 1 template <class T>
 2 class Singleton : public NonCopyable {
 3 private:
 4     static T* inst_;
 5 
 6 public:
 7     Singleton() {}
 8     virtual ~Singleton() {}
 9 
10     static T& inst()
11     {
12         if (!inst_) inst_ = new T;
13         return *inst_;
14     }
15 
16     static void uninst()
17     {
18         if (!inst_) return;
19         delete inst_;
20         inst_ = nullptr;
21     }
22 
23 };
24 //__declspec(selectany)声明使得我们可以在头文件中初始化一个全局变量
25 template <class T> __declspec(selectany)  T * Singleton<T>::inst_ = nullptr;

Copiar codigo

Implementación de clase singleton personalizada:

Copiar codigo

 1 class singletontest :public Singleton<singletontest>
 2 {
 3 public:
 4 singletontest(){ printf("singletontest constructor function called "); }
 5 ~singletontest(){ printf("class test object destroyed "); }
 6 //成员方法
 7 void print(){
 8 printf("singletontest::print function called ");
 9 }
10 };

Copiar codigo

Código de prueba:

Copiar codigo

1 singletontest::inst().print(); //line1
2 singletontest a;  //line 2 无法阻止默认构造,理想中,单例类只允许出现类似line1的调用
3 printf("singletontest obj a addr is %d\n", &a);
4 a.print();
5 singletontest b;
6 printf("singletontest obj b addr is %d\n", &b);
7 b.print();
8 //a(b);   //singletontest继承了noncopyable,继承类初始化时先调用父类的构造函数,由于定义成私有,所以构造失败
9 //a = b;  //同上,赋值运算操作符函数同样是私有的

Copiar codigo

 

Resultados de la prueba:

Después de que se escribe la línea de código line2, no se informa ningún error durante la compilación, lo que significa que el objeto se genera utilizando la estructura predeterminada. Para evitar este comportamiento, el constructor predeterminado debe establecerse como privado, pero la nueva T en el método inst () fallará y la ganancia no vale la pena perder.

El compilador puede identificar errores en el código de prueba de las líneas 8 y 9.

Hay una cadena de herencia de tres niveles (singletontest-> singleton <T> -> Noncopiable) en el código, pero debido a que no hay una función virtual declarada en la clase, no hay una solución alternativa en el método de llamada, por lo que no hay pérdida de rendimiento.

Singletontest: public sington <singletontest> está escrito como CRTP (patrón de plantilla curiosamente recurrente), que a menudo se utiliza para implementar polimorfismo estático. Este artículo no introducirá demasiado.

Finalmente, cuando se habla de la creación de una clase singleton en un entorno multiproceso, a menudo hay dos formas de estilo completo y estilo hambriento, pero C ++ moderno ha garantizado la seguridad de subprocesos de la creación de variables miembro estáticas, por lo que no hay discusión sobre este método. Necesario

Supongo que te gusta

Origin blog.csdn.net/qingzhuyuxian/article/details/108485174
Recomendado
Clasificación