Variables estáticas en funciones miembro

158

¿Alguien puede explicar cómo funcionan las variables estáticas en las funciones miembro en C ++?

Dada la siguiente clase:

class A {
   void foo() {
      static int i;
      i++;
   }
}

Si declaro varias instancias de A, ¿llamar foo()a una instancia incrementa la variable estática ien todas las instancias? ¿O solo el que fue llamado?

Supuse que cada instancia tendría su propia copia i, pero al pasar por algún código que tengo parece indicar lo contrario.

monofonik
fuente

Respuestas:

169

Dado que class Aes una clase sin plantilla y A::foo()es una función sin plantilla. Solo habrá una copia del static int iprograma.

Cualquier instancia de Aobjeto afectará lo mismo iy la vida útil de ipermanecerá durante todo el programa. Para agregar un ejemplo:

A o1, o2, o3;
o1.foo(); // i = 1
o2.foo(); // i = 2
o3.foo(); // i = 3
o1.foo(); // i = 4
iammilind
fuente
3
Gracias por el buen ejemplo! ¿Habría una manera de lograr algo que haga que el alcance sea static int iespecífico para la instancia, de modo que, por ejemplo, o1.foo(); // i = 1y $o2.foo(); // i = 1...?
Stingery
14
Aunque este puede no ser el estilo que está buscando, hacer que un miembro de datos privados de la clase A tenga el efecto que está describiendo. Si le preocupan los conflictos de nombres, puede agregar un prefijo como m_para indicar el estado de i.
Carl Morris
137

La palabra clave staticdesafortunadamente tiene algunos significados diferentes no relacionados en C ++

  1. Cuando se usa para miembros de datos significa que los datos se asignan en la clase y no en instancias.

  2. Cuando se usa para datos dentro de una función, significa que los datos se asignan estáticamente, se inicializan la primera vez que se ingresa el bloque y duran hasta que se cierra el programa. Además, la variable solo es visible dentro de la función. Esta característica especial de las estadísticas locales a menudo se usa para implementar la construcción perezosa de singletons.

  3. Cuando se usa en un nivel de unidad de compilación (módulo) significa que la variable es como una global (es decir, asignada e inicializada antes de mainejecutarse y destruirse después de las mainsalidas) pero que la variable no será accesible ni visible en otras unidades de compilación .

Agregué énfasis en la parte que es más importante para cada uso. Se desaconseja el uso (3) a favor de espacios de nombres sin nombre que también permiten declaraciones de clase no exportadas.

En su código, la staticpalabra clave se usa con el significado número 2 y no tiene nada que ver con clases o instancias ... es una variable de la función y solo habrá una copia de ella.

Como dijo correctamente iammilind , sin embargo, podría haber habido múltiples instancias de esa variable si la función fuera una función de plantilla (porque en ese caso, de hecho, la función en sí misma puede estar presente en muchas copias diferentes en el programa). Incluso en ese caso, por supuesto, las clases y las instancias son irrelevantes ... vea el siguiente ejemplo:

#include <stdio.h>

template<int num>
void bar()
{
    static int baz;
    printf("bar<%i>::baz = %i\n", num, baz++);
}

int main()
{
    bar<1>(); // Output will be 0
    bar<2>(); // Output will be 0
    bar<3>(); // Output will be 0
    bar<1>(); // Output will be 1
    bar<2>(); // Output will be 1
    bar<3>(); // Output will be 1
    bar<1>(); // Output will be 2
    bar<2>(); // Output will be 2
    bar<3>(); // Output will be 2
    return 0;
}
6502
fuente
41
+1 para keyword static unfortunately has a few different unrelated meanings in C++:)
iammilind
el mundo tiene mucho más sentido después de leer esto, GRACIAS
Erin
Me gusta el truco con las plantillas. No puedo esperar para encontrar una excusa para usarlo.
Tomáš Zato - Restablece a Monica el
¿Alguien tiene una referencia para "algo desanimado a favor de espacios de nombres sin nombre"?
austinmarton
3
@austinmarton: La frase "El uso de static para indicar 'local to unit unit' está en desuso en C ++. En su lugar, usar espacios de nombres sin nombre (8.2.5.1)" está presente en The C ++ Programming Language en mi edición (10ª impresión, septiembre de 1999) en la página 819.
6502
2

Variables estáticas dentro de funciones

  • La variable estática se crea dentro de una función que se almacena en la memoria estática del programa, no en la pila.

  • La inicialización de la variable estática se realizará en la primera llamada de la función.

  • La variable estática retendrá el valor en múltiples llamadas a funciones

  • La vida útil de la variable estática es Programa

ingrese la descripción de la imagen aquí

Ejemplos

#include <iostream>

using namespace std;

class CVariableTesting 
{
    public:
    
    void FuncWithStaticVariable();
    void FuncWithAutoVariable();

};

void CVariableTesting::FuncWithStaticVariable()
{
    static int staticVar = 0; //staticVar is initialised by 0 the first time
    cout<<"Variable Value : "<<staticVar<<endl;
    staticVar++;
}
void CVariableTesting::FuncWithAutoVariable()
{
    int autoVar = 0;
    cout<<"Variable Value : "<<autoVar<<endl;
    autoVar++;
}
    

int main()
{
    CVariableTesting objCVariableTesting;
    cout<<"Static Variable";
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    
    cout<<endl;
    cout<<"Auto Variable";
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    
    return 0;
}

Salida:

Variable estática

Valor variable: 0
Valor variable: 1
Valor variable: 2
Valor variable: 3
Valor variable: 4

Variable automática

Valor variable: 0
Valor variable: 0
Valor variable: 0
Valor variable: 0
Valor variable: 0

Saurabh Raoot
fuente
-2

Respuesta simplificada:

Las variables estáticas, independientemente de si son miembros de una función (sin plantilla) classo una función (sin plantilla), se comportan, técnicamente, como una etiqueta global cuyo alcance está limitado a la classfunción o.

0xbadf00d
fuente
9
No. Los globales se inicializan al inicio del programa, las estadísticas de funciones se inicializan al primer uso. Esta es una gran diferencia.
6502
No creo que esto sea lo que pasa. Sin embargo, esto debería ser específico del compilador de todos modos.
0xbadf00d
2
Entonces piensa mal: 3.6.1 en el estándar C ++ dicta que la construcción del objeto del alcance del espacio de nombres con una duración de almacenamiento estático ocurre al inicio; 6.7 (4) dicta que en general "... una variable de este tipo se inicializa la primera vez que el control pasa por su declaración; dicha variable se considera inicializada al finalizar su inicialización". Por cierto, esta inicialización en el primer uso es muy útil para implementar la construcción de singleton perezosa.
6502
3.7.4: "La inicialización constante (3.6.2) de una entidad de alcance de bloque con una duración de almacenamiento estático, si corresponde, se realiza antes de que su bloque se ingrese por primera vez. Una implementación puede realizar una inicialización temprana de otras variables de alcance de bloque con duración del almacenamiento estático o de subprocesos en las mismas condiciones en que se permite que una implementación inicialice estáticamente una variable con duración de almacenamiento estático o de subprocesos en el ámbito del espacio de nombres (3.6.2). De lo contrario, dicha variable se inicializa la primera vez que el control pasa por su declaración; "
0xbadf00d
1
Sin embargo, curiosamente: 1) para la inicialización constante es irrelevante discutir si una estática local puede inicializarse antes de ingresar al bloque la primera vez (la variable solo es visible dentro del bloque y la inicialización constante no produce efectos secundarios); 2) nada en su publicación se dice sobre la inicialización constante; 3) las estadísticas locales son muy útiles para una inicialización no constante como MyClass& instance(){ static MyClass x("config.ini"); return x; }: una implementación portátil válida para uso de un solo hilo exactamente porque las estadísticas locales NO son simplemente globales a pesar de lo que usted dice.
6502