acabando con el patrón singleton - wordpress.com · 2014-12-05 · christopher alexander....
TRANSCRIPT
Acabando con el patrón singleton
Acabando con el patrón singletonusing std::cpp 2014
J. Daniel Garcia
Grupo ARCOSUniversidad Carlos III de Madrid
28 de Octubre de 2014
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 1/55
Acabando con el patrón singleton
Aviso
c Esta obra está bajo una Licencia Creative CommonsAtribución-NoComercial-SinDerivar 4.0 Internacional.
b Debes dar crédito en la obra en la forma especificadapor el autor o licenciante.
e El licenciante permite copiar, distribuir y comunicar pú-blicamente la obra. A cambio, esta obra no puede serutilizada con fines comerciales — a menos que se ob-tenga el permiso expreso del licenciante.
d El licenciante permite copiar, distribuir, transmitir y co-municar públicamente solamente copias inalteradas dela obra – no obras derivadas basadas en ella.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 2/55
Acabando con el patrón singleton
Introducción
1 Introducción
2 El patrón Singleton
3 Ejemplos en la biblioteca estándar
4 La sencillez de los singleton
5 Revisitando el patrón
6 Detalles
7 Conclusiones
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 3/55
Acabando con el patrón singleton
Introducción
Diseño de software
Existen dos formas de construir un diseño desoftware: simplificándolo hasta el punto que resulteobvio que no hay en el errores o complicándolo de talforma que los errores que haya en el no sean obvios.
El primer método es mucho mas difícil.
Sir Tony Hoare, Premio Turing 1980.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 4/55
Acabando con el patrón singleton
Introducción
Diseño de software
Existen dos formas de construir un diseño desoftware: simplificándolo hasta el punto que resulteobvio que no hay en el errores o complicándolo de talforma que los errores que haya en el no sean obvios.
El primer método es mucho mas difícil.
Sir Tony Hoare, Premio Turing 1980.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 4/55
Acabando con el patrón singleton
Introducción
¿Importa el diseño?
¿Dónde te gustaría vivir?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 5/55
Acabando con el patrón singleton
Introducción
Lenguajes de Patrones
1977: A Pattern Language: Towns, Buildings, Construction.1979: The timeless Way of buildings.Christopher Alexander.
Introduce las nociones de patrón y lenguaje de patrones.Es un libro de arquitectura y edificación.Buscaba definir reglas paso-a-paso para resolverproblemas comunes de ingeniería en la creación deedificios y ciudades.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 6/55
Acabando con el patrón singleton
Introducción
GoF: The Gang of Four
1991: Gamma → Idea de patronessoftware.
1993: GoF envían un catálogo de patronesal ECOOP.
Design Patterns: Abstraction and Reuseof Object-Oriented Design. E. Gamma, R.Helm, R. Johnson, J. Vlissides. ECOOP,LNCS 707, pp. 406–431.
1995: Desing Patterns elements ofReusable Object-Oriented Software.
Más de un millón de copias vendidas.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 7/55
Acabando con el patrón singleton
Introducción
GoF: The Gang of Four
1991: Gamma → Idea de patronessoftware.1993: GoF envían un catálogo de patronesal ECOOP.
Design Patterns: Abstraction and Reuseof Object-Oriented Design. E. Gamma, R.Helm, R. Johnson, J. Vlissides. ECOOP,LNCS 707, pp. 406–431.
1995: Desing Patterns elements ofReusable Object-Oriented Software.
Más de un millón de copias vendidas.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 7/55
Acabando con el patrón singleton
Introducción
GoF: The Gang of Four
1991: Gamma → Idea de patronessoftware.1993: GoF envían un catálogo de patronesal ECOOP.
Design Patterns: Abstraction and Reuseof Object-Oriented Design. E. Gamma, R.Helm, R. Johnson, J. Vlissides. ECOOP,LNCS 707, pp. 406–431.
1995: Desing Patterns elements ofReusable Object-Oriented Software.
Más de un millón de copias vendidas.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 7/55
Acabando con el patrón singleton
Introducción
GoF: Catálogo
CreaciónAbstract Factory.Builder.Factory Method.Prototype.Singleton.
EstructuralAdapter.Bridge.Composite.Decorator.Facade.Flyweight.
Proxy.Comportamiento
Chain of Responsibility.Command.Interpreter.Iterator.Mediator.Memento.Observer.State.Strategy.Template Method.Visitor.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 8/55
Acabando con el patrón singleton
El patrón Singleton
1 Introducción
2 El patrón Singleton
3 Ejemplos en la biblioteca estándar
4 La sencillez de los singleton
5 Revisitando el patrón
6 Detalles
7 Conclusiones
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 9/55
Acabando con el patrón singleton
El patrón Singleton
Patrones de creación
Un patrón de creación ofrece flexibilidad sobre:¿Qué debe crearse?¿Quién lo crea?¿Cómo se crea?¿Cuándo se crea?¿Quién lo destruye?¿Cómo se destruye?¿Cuándo se destruye?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 10/55
Acabando con el patrón singleton
El patrón Singleton
Singleton
Intención: Asegurar que una clase tiene una únicainstancia y ofrecer un punto de acceso global a la misma.
Aplicabilidad:Debe haber exactamente una instancia de la clase, y debeser accesible a los clientes desde un punto de acceso bienconocido.Cuando una única instancia debe ser extensible (mediantesubclases) y los clientes deberían poder extender lainstancia sin modificar su código.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 11/55
Acabando con el patrón singleton
El patrón Singleton
Consecuencias
Acceso controlado a la única instanciaEncapsula la instancia y controla el acceso de los clientes.
Espacio de nombres reducidoEvita la polución del espacio de nombres con variablesglobales.
Permite refinar operaciones y representaciónSe puede subclasificar la clase singleton.
Permite un número variable de instanciasSe puede configurar un número distinto de 1 con cambiosmínimos.
Más flexible que operaciones de clase (estáticas)Difícil de cambiar el diseño (poca flexibilidad).
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 12/55
Acabando con el patrón singleton
El patrón Singleton
Ejemplo canónico
single.h
#ifndef SINGLE_H#define SINGLE_H
class singleton {public:
static singleton ∗ instance() ;void op1();
protected:singleton () ;
private:static singleton ∗ psing;
};
#endif
single.cpp
#include "single.h"#include <iostream>
singleton ∗ singleton :: psing = nullptr ;
singleton ∗ singleton :: instance() {if (nullptr == psing) {
psing = new singleton;}return psing;
}
singleton :: singleton () {std :: cout << "singleton () " << std ::endl;
}
void singleton :: op1() {std :: cout << "op1()" << std ::endl;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 13/55
Acabando con el patrón singleton
El patrón Singleton
Preguntas
¿Qué debe crearse?Una única instancia del singleton.
¿Quién lo crea?El cliente que necesita usar el singleton.
¿Cómo se crea?Obteniendo acceso mediante instance.
¿Cuándo se crea?En la primera invoacación a instance.
¿Quién lo destruye?No se destruye.
¿Cómo se destruye?No se destruye.
¿Cuándo se destruye?No se destruye.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 14/55
Acabando con el patrón singleton
Ejemplos en la biblioteca estándar
1 Introducción
2 El patrón Singleton
3 Ejemplos en la biblioteca estándar
4 La sencillez de los singleton
5 Revisitando el patrón
6 Detalles
7 Conclusiones
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 15/55
Acabando con el patrón singleton
Ejemplos en la biblioteca estándar
errno
errno.h
extern int errno;
errno.cc
int errno;
Código de usuario
void g() {// ...if (read(fd0, buffer , n) < 0) {
switch (errno) {// ...
}}
}
read.cc (simplificado)
ssize_t read(int fd , void ∗ buf, size_t nb) {if (nbytes == 0) return 0;if ( fd < 0) {
errno = EBADF;return −1;
}if (buf == NULL) {
errno = EINVAL;return −1;
}
errno = ENOSYS;return −1;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 16/55
Acabando con el patrón singleton
Ejemplos en la biblioteca estándar
errno
errno.h
extern int errno;
errno.cc
int errno;
Código de usuario
void g() {// ...if (read(fd0, buffer , n) < 0) {
switch (errno) {// ...
}}
}
read.cc (simplificado)
ssize_t read(int fd , void ∗ buf, size_t nb) {if (nbytes == 0) return 0;if ( fd < 0) {
errno = EBADF;return −1;
}if (buf == NULL) {
errno = EINVAL;return −1;
}
errno = ENOSYS;return −1;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 16/55
Acabando con el patrón singleton
Ejemplos en la biblioteca estándar
errno
errno.h
extern int errno;
errno.cc
int errno;
Código de usuario
void g() {// ...if (read(fd0, buffer , n) < 0) {
switch (errno) {// ...
}}
}
read.cc (simplificado)
ssize_t read(int fd , void ∗ buf, size_t nb) {if (nbytes == 0) return 0;if ( fd < 0) {
errno = EBADF;return −1;
}if (buf == NULL) {
errno = EINVAL;return −1;
}
errno = ENOSYS;return −1;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 16/55
Acabando con el patrón singleton
Ejemplos en la biblioteca estándar
errno
errno.h
extern int errno;
errno.cc
int errno;
Código de usuario
void g() {// ...if (read(fd0, buffer , n) < 0) {
switch (errno) {// ...
}}
}
read.cc (simplificado)
ssize_t read(int fd , void ∗ buf, size_t nb) {if (nbytes == 0) return 0;if ( fd < 0) {
errno = EBADF;return −1;
}if (buf == NULL) {
errno = EINVAL;return −1;
}
errno = ENOSYS;return −1;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 16/55
Acabando con el patrón singleton
Ejemplos en la biblioteca estándar
Preguntas sobre errno
¿Qué debe crearse?Una única instancia de errno.
¿Quién lo crea?El enlazador.
¿Cómo se crea?Accediendo a la variable de programa.
¿Cuándo se crea?En arranque de programa.
¿Quién lo destruye?No se destruye.
¿Cómo se destruye?No se destruye.
¿Cuándo se destruye?No se destruye.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 17/55
Acabando con el patrón singleton
Ejemplos en la biblioteca estándar
Los singletons de la biblioteca estándar
iostream
namespace std {extern istream cin;extern ostream cout;extern ostream cerr;extern ostream clog;
static ios_base:: Init __ioinit ;}
globals_io.cc
namespace std {using istream_buffer =
char alignas(istream) [sizeof(istream) ];using ostream_buffer =
char alignas(istream) [sizeof(ostream)];istream_buffer_t cin ;ostream_buffer_t cout;ostream_buffer_t cerr;ostream_buffer_t clog;// ...
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 18/55
Acabando con el patrón singleton
Ejemplos en la biblioteca estándar
Los singletons de la biblioteca estándar
iostream
namespace std {extern istream cin;extern ostream cout;extern ostream cerr;extern ostream clog;
static ios_base:: Init __ioinit ;}
globals_io.cc
namespace std {using istream_buffer =
char alignas(istream) [sizeof(istream) ];using ostream_buffer =
char alignas(istream) [sizeof(ostream)];istream_buffer_t cin ;ostream_buffer_t cout;ostream_buffer_t cerr;ostream_buffer_t clog;// ...
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 18/55
Acabando con el patrón singleton
Ejemplos en la biblioteca estándar
Los singletons de la biblioteca estándar
iostream
namespace std {extern istream cin;extern ostream cout;extern ostream cerr;extern ostream clog;
static ios_base:: Init __ioinit ;}
globals_io.cc
namespace std {using istream_buffer =
char alignas(istream) [sizeof(istream) ];using ostream_buffer =
char alignas(istream) [sizeof(ostream)];istream_buffer_t cin ;ostream_buffer_t cout;ostream_buffer_t cerr;ostream_buffer_t clog;// ...
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 18/55
Acabando con el patrón singleton
Ejemplos en la biblioteca estándar
Iniciando los singletons
ios_base.h
namespace std {class ios_base {// ...
class Init {public:
Init () ;~ Init () ;
private:static atomic<int> refcount;
};// ...};
}
ios_init.cc
namespace std {
ios_base:: Init :: Init () {if (refcount.fetch_add(1) == 0) {
new (&cout) ostream(&buf_cout_sync);new (&cin) ostream(&buf_cin_sync);new (&cerr) ostream(&buf_cerr_sync);new (&clog) ostream(&buf_cerr_sync);refcount.fetch_add(1);
}}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 19/55
Acabando con el patrón singleton
Ejemplos en la biblioteca estándar
Preguntas sobre cin, ...
¿Qué debe crearse?Una única instancia de cin, cout, ...
¿Quién lo crea?El cliente si usa el objeto.
¿Cómo se crea?Creando automáticamente el objeto estántico __ioinit.
¿Cuándo se crea?Al ejecutar el constructor de Init por primera vez.
¿Quién lo destruye?El destructor de Init.
¿Cómo se destruye?Al destruir el último objeto __ioinit.
¿Cuándo se destruye?A la finalización del programa.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 20/55
Acabando con el patrón singleton
La sencillez de los singleton
1 Introducción
2 El patrón Singleton
3 Ejemplos en la biblioteca estándar
4 La sencillez de los singleton
5 Revisitando el patrón
6 Detalles
7 Conclusiones
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 21/55
Acabando con el patrón singleton
La sencillez de los singleton
La interfaz de usuario
Usando un singleton para errno
void f () {// ...if (read(fd0, buffer , n) < 0) {
switch(errno_holder::instance()−>value()) {// ...
}}
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 22/55
Acabando con el patrón singleton
La sencillez de los singleton
Y si tuvieses que escribir esto...
Usando un singleton para errno
void f () {// ...(∗std :: cout−>instance()) << "Hola" << std::endl;// std :: cout << "Hola" << std ::endl;}
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 23/55
Acabando con el patrón singleton
La sencillez de los singleton
Otros problemas
La implementación no es tan sencilla como parece:Garantía de destrucción.Problemas de referencias muertas.Orden de destrucción de singletons.Problemas con múltiples hilos.
Discutidos en detalle en Modern C++ Design(Alexandrescu).
... que ya empieza a no ser tan moderno.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 24/55
Acabando con el patrón singleton
La sencillez de los singleton
¿Y Erich que opina de todo esto?
Question: How would you refactor Design Patterns?Answer:. . .
We have found that the object-oriented design principlesand most of the patterns haven’t changed since then.
. . .When discussing which patterns to drop, we found that westill love them all. (Not really – I’m in favor of droppingSingleton. Its use is almost always a design smell.)
Design Patterns 15 Years Later: An Interview with Erich Gamma,Richard Helm, and Ralph Johnson.
October, 2009.http://www.informit.com/articles/article.aspx?p=1404056
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 25/55
Acabando con el patrón singleton
Revisitando el patrón
1 Introducción
2 El patrón Singleton
3 Ejemplos en la biblioteca estándar
4 La sencillez de los singleton
5 Revisitando el patrón
6 Detalles
7 Conclusiones
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 26/55
Acabando con el patrón singleton
Revisitando el patrón
¿Estás seguro?
Tener una única instancia global es una singularidad.¿Es realmente necesario?Impide copias del objeto.Impide paso y retorno por valor.
Pocas veces la restricción tiene sentdio.¿Una única impresora?¿Un único log para la aplicación?
Más problemático en un mundo concurrente.En el mejor de los casos es una fuente de contención.En el peor de los casos es una fuente de carreras de datos.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 27/55
Acabando con el patrón singleton
Revisitando el patrón
Un log de eventos
evlog.h
#ifndef EVLOG_H#define EVLOG_H
#include <string>#include <vector>
class event_logger {public:
event_logger();~event_logger();
void log(const std:: string & m);void set_file_name(const std::string & m) { file_name = m; }void set_size(unsigned n) { size = n; }
private:void dump();
private:unsigned size = 4;std :: vector<std :: string> buffer ;std :: string file_name {"log. txt " };
};
#endif
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 28/55
Acabando con el patrón singleton
Revisitando el patrón
Implementando un log de eventos
evlog.cpp
#include "evlog.h"#include <fstream>
using namespace std;
event_logger::event_logger() {ofstream file {file_name, ios :: out | ios :: trunc };file << "Log started" << endl;
}
event_logger::~event_logger() {if ( buffer .size () > 0) {
dump();}ofstream file {file_name, ios :: app | ios :: out };file << "Log ended" << endl;
}
void event_logger::log(const std:: string & m) {if ( buffer .size () >= size) {
dump();}buffer .push_back(m);
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 29/55
Acabando con el patrón singleton
Revisitando el patrón
Implementando un log de eventos
evlog.cpp
void event_logger::dump() {ofstream file {file_name, ios :: app | ios :: out };for (auto && m : buffer) {
file << m << endl;}buffer . clear () ;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 30/55
Acabando con el patrón singleton
Revisitando el patrón
En ocasiones veo singletons
... incluso donde no los hay!
Nada debería impedir el uso de múltiples logs de eventos.
Aún así tomemos el caso como ejemplo.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 31/55
Acabando con el patrón singleton
Revisitando el patrón
Un log de eventos único
evlog.h
#ifndef EVLOG_H#define EVLOG_H
#include <string>#include <vector>
class event_logger {public:
static event_logger & instance();~event_logger();event_logger(const event_logger &) = delete;event_logger(event_logger &&) = delete;event_logger & operator=(const event_logger &) = delete;event_logger & operator=(event_logger &&) = delete;
private:event_logger();
public:void log(const std:: string & m);void set_file_name(const std::string & m) { file_name = m; }void set_size(unsigned n) { size = n; }
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 32/55
Acabando con el patrón singleton
Revisitando el patrón
Un log de eventos único
evlog.h
private:void dump();
private:unsigned size = 4;std :: vector<std :: string> buffer ;std :: string file_name {"log. txt " };
};
#endif
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 33/55
Acabando con el patrón singleton
Revisitando el patrón
Implementando un log de eventos único
evlog.cpp
#include "evlog.h"#include <fstream>
using namespace std;
event_logger & event_logger::instance() {static event_logger ev;return ev;
}
event_logger::event_logger() {ofstream file {file_name, ios :: out | ios :: trunc };file << "Log started" << endl;
}
event_logger::~event_logger() {if ( buffer .size () > 0) {
dump();}ofstream file {file_name, ios :: app | ios :: out };file << "Log ended" << endl;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 34/55
Acabando con el patrón singleton
Revisitando el patrón
Implementando un log de eventos único
evlog.cpp
void event_logger::log(const std:: string & m) {if ( buffer .size () >= size) {
dump();}buffer .push_back(m);
}
void event_logger::dump() {ofstream file {file_name, ios :: app | ios :: out };for (auto && m : buffer) {
file << m << endl;}buffer . clear () ;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 35/55
Acabando con el patrón singleton
Revisitando el patrón
Acceso a la instancia
Acceso controlado a la única instancia.El singleton ofrece un mecanismo de acceso global.
Una variable global también ofrece un mecanismo deacceso global.
El singleton permite controlar cada acceso al único objetoglobal.
Ejemplo: Registrar cada evento de uso.Pero nada impide que el cliente almacene una referencia alobjeto global.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 36/55
Acabando con el patrón singleton
Revisitando el patrón
Un log de eventos global
evlog.h
#ifndef EVLOG_H#define EVLOG_H
#include <string>
namespace logging {void log(const std:: string & name);void set_file_name(const std::string & m);void set_size(unsigned n);
}
#endif
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 37/55
Acabando con el patrón singleton
Revisitando el patrón
Implementando un log de eventos global
evlog.cpp
#include "evlog.h"#include <fstream>#include <vector>
namespace logging {
using namespace std;
namespace {unsigned size = 4;std :: vector<std :: string> buffer ;std :: string file_name = "log. txt " ;
void dump() {ofstream file {file_name, ios :: app | ios :: out };for (auto && m : buffer) {
file << m << endl;}buffer . clear () ;
}
} // Anonymous namespace
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 38/55
Acabando con el patrón singleton
Revisitando el patrón
Implementando un log de eventos global
evlog.cpp
void log(const std:: string & m) {if ( buffer .size () >= size) {
dump();}buffer .push_back(m);
}
void set_file_name(const std::string & n) {file_name = n;
}
void set_size(unsigned n) {size = n;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 39/55
Acabando con el patrón singleton
Revisitando el patrón
Implementando un log de eventos global
evlog.cpp
namespace {
class init {public:
init () {ofstream file {file_name, ios :: out | ios :: trunc };file << "Log started" << endl;
}
~ init () {if ( buffer .size () > 0) {
dump();}ofstream file {file_name, ios :: app | ios :: out };file << "Log ended" << endl;
}};
init initializer ;
} // Anonymous namespace
} // namespace logging
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 40/55
Acabando con el patrón singleton
Revisitando el patrón
Otras consideraciones
Espacio de nombres reducidos:Un uso efectivo de los namespace evita la polución delespacio de nombres global.
Refinamiento de operaciones y representación.Se puede ocultar destrás de una interfaz muy simple.
Dependencia entre singletons.Se puede gestionar mediante un gestor de inicicaciónúnico.Después de todo si hay dependencia entre singletons estosdeberían estar acoplados.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 41/55
Acabando con el patrón singleton
Detalles
1 Introducción
2 El patrón Singleton
3 Ejemplos en la biblioteca estándar
4 La sencillez de los singleton
5 Revisitando el patrón
6 Detalles
7 Conclusiones
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 42/55
Acabando con el patrón singleton
Detalles
Iniciación perezosa
6 DetallesIniciación perezosa¿Y qué pasa con la concurrencia?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 43/55
Acabando con el patrón singleton
Detalles
Iniciación perezosa
Problema
Se debería poder diferir la iniciación al primer uso.Y evitar la iniciación si no se llega a usar.
La solución: otro nivel adicional de indirección.All problems in computer science can be solved with anadditional level of indirection.... except the problems of too many levels of indirection(David Wheeler).
Añadiendo otro nivel de indirección.Solución trivial: memoria dinámica.Pero mejor evitar la memoria dinámica ¿no?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 44/55
Acabando con el patrón singleton
Detalles
Iniciación perezosa
Problema
Se debería poder diferir la iniciación al primer uso.Y evitar la iniciación si no se llega a usar.
La solución: otro nivel adicional de indirección.
All problems in computer science can be solved with anadditional level of indirection.... except the problems of too many levels of indirection(David Wheeler).
Añadiendo otro nivel de indirección.Solución trivial: memoria dinámica.Pero mejor evitar la memoria dinámica ¿no?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 44/55
Acabando con el patrón singleton
Detalles
Iniciación perezosa
Problema
Se debería poder diferir la iniciación al primer uso.Y evitar la iniciación si no se llega a usar.
La solución: otro nivel adicional de indirección.All problems in computer science can be solved with anadditional level of indirection.
... except the problems of too many levels of indirection(David Wheeler).
Añadiendo otro nivel de indirección.Solución trivial: memoria dinámica.Pero mejor evitar la memoria dinámica ¿no?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 44/55
Acabando con el patrón singleton
Detalles
Iniciación perezosa
Problema
Se debería poder diferir la iniciación al primer uso.Y evitar la iniciación si no se llega a usar.
La solución: otro nivel adicional de indirección.All problems in computer science can be solved with anadditional level of indirection.... except the problems of too many levels of indirection(David Wheeler).
Añadiendo otro nivel de indirección.Solución trivial: memoria dinámica.Pero mejor evitar la memoria dinámica ¿no?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 44/55
Acabando con el patrón singleton
Detalles
Iniciación perezosa
Problema
Se debería poder diferir la iniciación al primer uso.Y evitar la iniciación si no se llega a usar.
La solución: otro nivel adicional de indirección.All problems in computer science can be solved with anadditional level of indirection.... except the problems of too many levels of indirection(David Wheeler).
Añadiendo otro nivel de indirección.Solución trivial: memoria dinámica.Pero mejor evitar la memoria dinámica ¿no?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 44/55
Acabando con el patrón singleton
Detalles
Iniciación perezosa
Una interfaz sencilla
evlog.h
#ifndef EVLOG_H#define EVLOG_H
#include <string>
namespace logging {void log(const std:: string & name);void set_file_name(const std::string & m);void set_size(unsigned n);
}
#endif
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 45/55
Acabando con el patrón singleton
Detalles
Iniciación perezosa
Una clase invisible, pero normal
evlog.cpp
#include "evlog.h"#include <fstream>#include <vector>
namespace logging {
using namespace std;
namespace {
class event_logger {public:
event_logger();~event_logger();void log(const string & m);void set_file_name(const string & n) { file_name=n; }void set_size(unsigned s) { size=s; }
private:void dump();
private:unsigned size = 4;vector<string> buffer ;string file_name = "log. txt " ;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 46/55
Acabando con el patrón singleton
Detalles
Iniciación perezosa
Una clase invisible, pero normal
evlog.cpp
event_logger::event_logger() {ofstream file {file_name, ios :: out | ios :: trunc };file << "Log started" << endl;
}
event_logger::~event_logger() {if ( buffer .size () > 0) {
dump();}ofstream file {file_name, ios :: app | ios :: out };file << "Log ended" << endl;
}
void event_logger::log(const string & m) {if ( buffer .size () >= size) {
dump();}buffer .push_back(m);
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 47/55
Acabando con el patrón singleton
Detalles
Iniciación perezosa
Una clase invisible, pero normal
evlog.cpp
void event_logger::dump() {ofstream file {file_name, ios :: app | ios :: out };for (auto && m : buffer) {
file << m << endl;}buffer . clear () ;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 48/55
Acabando con el patrón singleton
Detalles
Iniciación perezosa
otro nivel de indirección
evlog.cpp
char logger alignas(event_logger) [sizeof(event_logger)];event_logger ∗ plogger = nullptr;
struct init {init () {
plogger = new (&logger) event_logger{};}
~ init () {plogger−>~event_logger();plogger = nullptr ;
}
};
void do_init () {static init i ;
}
} // Anonymous namespace
void log(const std:: string & m) {do_init () ;
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 49/55
Acabando con el patrón singleton
Detalles
Iniciación perezosa
El resto es simple
evlog.cpp
}
void set_file_name(const std::string & n) {do_init () ;plogger−>set_file_name(n);
}
void set_size(unsigned n) {do_init () ;plogger−>set_size(n);
}
} // namespace logging
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 50/55
Acabando con el patrón singleton
Detalles
¿Y qué pasa con la concurrencia?
6 DetallesIniciación perezosa¿Y qué pasa con la concurrencia?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 51/55
Acabando con el patrón singleton
Detalles
¿Y qué pasa con la concurrencia?
Iniciación concurrente de variables estáticas
Section 6.7.4:If control enters the declaration concurrently while thevariable is being initialized, the concurrent executionshall wait for completion of the initialization.
Olvídate del Double Checked Locking Pattern.Todavía tienes que hacer que event_logger seathread-safe.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 52/55
Acabando con el patrón singleton
Conclusiones
1 Introducción
2 El patrón Singleton
3 Ejemplos en la biblioteca estándar
4 La sencillez de los singleton
5 Revisitando el patrón
6 Detalles
7 Conclusiones
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 53/55
Acabando con el patrón singleton
Conclusiones
Conclusiones
Los patrones de diseño son buenas prácticas usadasrecurrentemente.
¿Es singleton patrón o anti-patrón?La biblioteca estándar no lo usa ni una sola vez.
Hay soluciones alternativas.
En el fondo el singleton es una manera enrevesada desimular una variable global.
Pero C++ ya tiene variables globales.Piensa en la pesadilla sintáctica sin cout fuese unsingleton.
Si no te fías de mi, fíate de Erich Gamma.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 54/55
Acabando con el patrón singleton
Conclusiones
Conclusiones
Los patrones de diseño son buenas prácticas usadasrecurrentemente.
¿Es singleton patrón o anti-patrón?
La biblioteca estándar no lo usa ni una sola vez.
Hay soluciones alternativas.
En el fondo el singleton es una manera enrevesada desimular una variable global.
Pero C++ ya tiene variables globales.Piensa en la pesadilla sintáctica sin cout fuese unsingleton.
Si no te fías de mi, fíate de Erich Gamma.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 54/55
Acabando con el patrón singleton
Conclusiones
Conclusiones
Los patrones de diseño son buenas prácticas usadasrecurrentemente.
¿Es singleton patrón o anti-patrón?La biblioteca estándar no lo usa ni una sola vez.
Hay soluciones alternativas.En el fondo el singleton es una manera enrevesada desimular una variable global.
Pero C++ ya tiene variables globales.Piensa en la pesadilla sintáctica sin cout fuese unsingleton.
Si no te fías de mi, fíate de Erich Gamma.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 54/55
Acabando con el patrón singleton
Conclusiones
Conclusiones
Los patrones de diseño son buenas prácticas usadasrecurrentemente.
¿Es singleton patrón o anti-patrón?La biblioteca estándar no lo usa ni una sola vez.
Hay soluciones alternativas.
En el fondo el singleton es una manera enrevesada desimular una variable global.
Pero C++ ya tiene variables globales.Piensa en la pesadilla sintáctica sin cout fuese unsingleton.
Si no te fías de mi, fíate de Erich Gamma.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 54/55
Acabando con el patrón singleton
Conclusiones
Conclusiones
Los patrones de diseño son buenas prácticas usadasrecurrentemente.
¿Es singleton patrón o anti-patrón?La biblioteca estándar no lo usa ni una sola vez.
Hay soluciones alternativas.En el fondo el singleton es una manera enrevesada desimular una variable global.
Pero C++ ya tiene variables globales.Piensa en la pesadilla sintáctica sin cout fuese unsingleton.
Si no te fías de mi, fíate de Erich Gamma.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 54/55
Acabando con el patrón singleton
Conclusiones
Conclusiones
Los patrones de diseño son buenas prácticas usadasrecurrentemente.
¿Es singleton patrón o anti-patrón?La biblioteca estándar no lo usa ni una sola vez.
Hay soluciones alternativas.En el fondo el singleton es una manera enrevesada desimular una variable global.
Pero C++ ya tiene variables globales.
Piensa en la pesadilla sintáctica sin cout fuese unsingleton.
Si no te fías de mi, fíate de Erich Gamma.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 54/55
Acabando con el patrón singleton
Conclusiones
Conclusiones
Los patrones de diseño son buenas prácticas usadasrecurrentemente.
¿Es singleton patrón o anti-patrón?La biblioteca estándar no lo usa ni una sola vez.
Hay soluciones alternativas.En el fondo el singleton es una manera enrevesada desimular una variable global.
Pero C++ ya tiene variables globales.Piensa en la pesadilla sintáctica sin cout fuese unsingleton.
Si no te fías de mi, fíate de Erich Gamma.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 54/55
Acabando con el patrón singleton
Conclusiones
Conclusiones
Los patrones de diseño son buenas prácticas usadasrecurrentemente.
¿Es singleton patrón o anti-patrón?La biblioteca estándar no lo usa ni una sola vez.
Hay soluciones alternativas.En el fondo el singleton es una manera enrevesada desimular una variable global.
Pero C++ ya tiene variables globales.Piensa en la pesadilla sintáctica sin cout fuese unsingleton.
Si no te fías de mi, fíate de Erich Gamma.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 54/55
Acabando con el patrón singleton
Conclusiones
Acabando con el patrón singletonusing std::cpp 2014
J. Daniel Garcia
Grupo ARCOSUniversidad Carlos III de Madrid
28 de Octubre de 2014
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) 55/55