Pregunta

Recibo este error

error: Access.Core may be used uninitialized in this function

Y este es mi código:

 static int FirstTime = 1;
 MyStruct Access;

 if (FirstTime) {
   FirstTime = 0;
   Access = Implementation();
   DoSomething(Access);
 }

 if(Other_Variable) {
    Access = Implementation2();
    DoSomething(Access);
  }

  //The Other_Variable will be set to 1 and to 0 by other part of the code

Mi código es así porque quiero llamar a la implementación de la función solo la primera vez. En cada llamada, la variable de acceso se actualizará, por lo que no tiene mucho sentido hacerlo estático.

Si hago que Access estático funcione, pero no me gusta hacerlo estático porque en todas las demás llamadas, Access se actualizará. ¿Alguna forma de evitar el problema sin hacerlo estático?

También cualquier opción mejor para ejecutar solo una vez que una función en lugar de usar una variable estática es bienvenida.

¿Fue útil?

Solución

Realice Access de esta manera (y elimine FirstTime y if ):

static MyStruct Access = Implementation(this_b);

La razón por la que recibe esta advertencia es porque las variables estáticas sobreviven a una llamada de función. Su valor se retiene en todas las llamadas a funciones ( sin con respecto a qué hilo llama a esa función). Por lo tanto, FirstTime controlará si inicializa Access . La primera vez que llame a la función en la que se encuentra el código, se inicializará correctamente la variable Access . Pero con cada llamada de función adicional, FirstTime es cero, y no inicializará Access , y por lo tanto usará una variable no inicializada en el código .

Editar: Ahora, con su información actualizada, dice que tiene dos funciones Implementation . La primera vez que quiera usar una, y todas las demás veces que quiera usar otra función. ¿Qué tal esto entonces:

 // static will be false/zero by default
 static bool AlreadyCalled;
 MyStruct Access;

 if (!AlreadyCalled) {
   Access = Implementation();
   AlreadyCalled = true;
 } else {
   Access = Implementation2();
 }

Dependiendo de su caso de uso real, puede haber mejores formas de manejar esto. Por ejemplo, ¿por qué no actualizar el estado de Access , así:

// let the default constructor initialize it
// to a plausible state
static MyStruct Access;

// use RAII to update the state of Access when this
// function returns. 
MyUpdater updater(Access);

// now, do whatever the function does. 

Algo así para MyUpdater :

struct MyUpdater {
    MyStruct &s;
    MyUpdater(MyStruct &s):s(s) { }
    ~MyUpdater() {
        s.ChangeState();
    }
};

Ese patrón se llama RAII : Asocia alguna acción útil con el constructor y destructor de un objeto asignado localmente.

Otros consejos

La respuesta de

@ litb es interesante. Sigue un programa equivalente. El código se compila y funciona como se indica en C ++, pero no se compila en C.

#include <stdio.h>

static int newval(void) { return 3; }

void inc(void)
{
    static int a = newval();

    a++;
    printf("%d\n", a);
}

int main(void)
{
    int i;
    for (i = 0; i < 10; i++)
        inc();
    return(0);
}

gcc dice:

x.c: en la función 'inc': x.c: 7: error: el elemento inicializador no es constante

g ++ está bastante contento con eso.

Esa es una diferencia entre C y C ++ que no conocía (pero esto no cabía en 300 caracteres, así que no puedo hacer un comentario, fácilmente).


@Eduardo hizo una de las preguntas en los comentarios: "¿Por qué C no permite esto y C ++ lo permite?". Dado que la respuesta tiene más de 300 caracteres ...

Como @litb dijo en los comentarios, en C solo puede usar constantes para inicializadores de variables estáticas. Esto se debe en parte a que los valores se establecen antes de que se llame a main (), y no se invocan funciones definidas por el usuario antes de que se llame a main (). C ++, por el contrario, permite que los constructores (definidos por el usuario) inicialicen las variables globales y estáticas antes de que se llame a main (), por lo que no hay razón para no permitir que también se invoquen otras funciones definidas por el usuario, por lo que la inicialización es razonable. Con C89, está limitado en los inicializadores que puede usar con variables automáticas (locales); en C99, puede usar prácticamente cualquier expresión para inicializar cualquier variable local.

El acceso no es estático, por lo tanto, se crea una nueva instancia cada vez que se llama a la función. Solo en la primera vez que realmente le asignas algún valor; este valor se pierde en cuanto sale la función.

Si necesita acceso para persistir en las llamadas a la función, hágalo estático.

Access no es estático y, por lo tanto, debe crearse en cada llamada.

Considere simplificar el código a algo como:

static MyStruct Access = Implementation(this_b);

Esto asegura que la función solo se llamará la primera vez que se ejecute el método y que Access mantendrá el valor entre llamadas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top