Cita de: zupervacaPor lo mismo que por que no se sepa por que funciona no significa que este mal hecho.Cuando el autor no sabe explicar por qué funciona, tampoco puede GARANTIZAR que vaya a seguir funcionando mañana, y por tanto su trabajo no está bien hecho (a no ser que te paguen por hacer algo y solo te exijan que funcione "hoy" ;)). Y, como vamos a ver más abajo, cuando la razon por la que funciona es "implementation dependent" o "por pura casualidad", entonces ESTA mal hecho, sepas o no sepas por qué.
Cita de: zupervacaEl por que funciona es simple, la clase singleton alberga un miembro estatico, pero la instancia de la clase en si no es estatica por lo que al indicarlas en la funcion main se asignan como memoria automatica, es decir, en la pila, y la pila tiene un orden muy estricto, el primero en destruirse es el ultimo en crearse, y ya que el estandar c++ indica que las instancias de las clases solo se inicializan cuando son llamadas por primera vez el orden se vuelve correctoNi de coña.
"For the static member to exist, it is not necessary that any objects of the class type exist"
Las variables estáticas de una funcion son inicializadas la primera vez que se ejecuta la función, ni antes ni despues. Para las estáticas de clase eso no es aplicable, porque ni siquiera hace falta que exista una instancia de la clase para que la estática de esa clase exista.
"Initialization of global static objects in a translation unit. This may occur either before entry to main or before the first use of any function or object in the object's translation unit."
Las variables estáticas de una clase se pueden inicializar mucho antes y en un orden no definido por el estándar. Lo curioso es que los templates en general ni siquiera viven en una translation unit concreta, sino (generalmente) como multiples en una amalgama de "translation units" en las que se usa ese template, y que el linker se ocupa de fundir en una sola copia.
La presencia de las instancias en la pila no tiene NADA que ver. La realidad? Funciona en tu ejemplo solamente por la forma en que el compilador / linker generan el código asociado al template en ese caso concreto. Tu ejemplo es tremendamente fácil de destrozar:
Código [Seleccionar]
#include <stdio.h>
template <class TYPE> class Singleton
{
static TYPE object;
public:
TYPE *operator -> () { return &this->object; }
};
template <class TYPE> TYPE Singleton<TYPE>::object;
struct A { A() { puts("A::A()"); } ~A() { puts("A::~A()"); } void f() {puts("A::f()"); } };
struct B { B() { puts("B::B()"); } ~B() { puts("B::~B()"); } void f() {puts("B::f()"); } };
void f()
{
Singleton<B> b;
puts("f()");
b->f();
}
int main()
{
Singleton<A> a;
Singleton<B> b;
a->f();
b->f();
f();
return 0;
}Y la salida de ese programa es:
Código [Seleccionar]
B::B()
A::A()
A::f()
B::f()
f()
B::f()
A::~A()
B::~B()
Como puedes ver, el orden de los singletons en main() es A y luego B, sin embargo las llamadas a los constructores de esas clases ocurren en orden inverso. Por qué? Porque lo que dices simplemente NO ES CIERTO, aunque en determinados casos funcione por casualidad. Mejor dejarse de filigranas que ni funcionan ni responden a una regla establecida y estandarizada. Globales con inicialización explÃcita y a vivir que son dos dÃas.
PD: Joer que destrozo hace el foro con los acentos y tal. :(
