Question

J'ai une classe avec méthode statique qui a une variable statique locale. Je veux cette variable à calculer / évaluée une fois (la 1ère fois que j'appelle la fonction) et pour toute invocation ultérieure, il n'est pas évalué plus. Comment faire ça? Voici ma classe:

template<
    typename T1 = int, unsigned N1 = 1,
    typename T2 = int, unsigned N2 = 0,
    typename T3 = int, unsigned N3 = 0,
    typename T4 = int, unsigned N4 = 0,
    typename T5 = int, unsigned N5 = 0,
    typename T6 = int, unsigned N6 = 0,
    typename T7 = int, unsigned N7 = 0,
    typename T8 = int, unsigned N8 = 0,
    typename T9 = int, unsigned N9 = 0,
    typename T10 = int, unsigned N10 = 0,
    typename T11 = int, unsigned N11 = 0,
    typename T12 = int, unsigned N12 = 0,
    typename T13 = int, unsigned N13 = 0,
    typename T14 = int, unsigned N14 = 0,
    typename T15 = int, unsigned N15 = 0,
    typename T16 = int, unsigned N16 = 0>
struct GroupAlloc
{
    static const uint32_t sizeClass;
    static uint32_t getSize()
    {
        static uint32_t totalSize = 0;

        totalSize += sizeof(T1)*N1;
        totalSize += sizeof(T2)*N2;
        totalSize += sizeof(T3)*N3;
        totalSize += sizeof(T4)*N4;

        totalSize += sizeof(T5)*N5;
        totalSize += sizeof(T6)*N6;
        totalSize += sizeof(T7)*N7;
        totalSize += sizeof(T8)*N8;

        totalSize += sizeof(T9)*N9;
        totalSize += sizeof(T10)*N10;
        totalSize += sizeof(T11)*N11;
        totalSize += sizeof(T12)*N12;

        totalSize += sizeof(T13)*N13;
        totalSize += sizeof(T14)*N14;
        totalSize += sizeof(T15)*N15;
        totalSize += sizeof(T16)*N16;

        totalSize = 8*((totalSize + 7)/8);

        return totalSize;
    }
};

EDIT:

Merci à tous pour votre aide rapide. +1 à tout le monde. J'ai choisi la réponse de Tyler McHenry, car il n'a pas besoin de comparaison, purement évaluation de la fonction statique. Je besoin de ce code pour allocateur Évitant une autre « si » devrait être mieux. Merci encore!

EDIT:

La réponse de gf avéré être le meilleur comme il oeuvre dans ces missions pendant la compilation et enregistre le programme de maux de tête et l'initialisation explicite thread-safe. Cependant, je respecte la meilleure réponse précédente. Je donnerai crédit ici au lieu de changer la coche. Merci à tous pour aider!

Était-ce utile?

La solution

Faire une autre fonction statique qui fait le calcul, et l'utiliser pour l'initialisation de la variable, par exemple.

static uint32_t computeSize() 
{
  uint32_t init_totalSize;

  // Lots of code

  return init_totalSize;
}

static uint32_t getSize()
{
  static uint32_t totalSize = computeSize();
  return totalSize;
}

Les variables statiques sont garanties à initialiser exactement une fois (la première fois la fonction qui les contient est utilisée).

Modifier Mais est pas thread-safe. Cette page explique en détail .

Pour le rendre thread-safe, il ne suffit pas d'envelopper l'initialisation de totalSize (l'appel à computeSize) dans une section critique, car l'initialisation variable statique est « la magie du compilateur », et il se peut que la variable subit initialisation à tout moment pendant l'appel à getSize avant qu'il ne soit utilisé, même avant la première déclaration de la fonction. Ce que vous devez faire est de prévenir plus d'un fil de même appeler getSize en même temps, ce qui peut être accompli avec un autre niveau d'indirection, par exemple.

static uint32_t computeSize() 
{
  uint32_t init_totalSize;

  // Lots of code

  return init_totalSize;
}

static uint32_t real_getSize()
{
  static uint32_t totalSize = computeSize();
  return totalSize;
}

static uint32_t getSize()
{
  uint32_t totalSize;
  /* --- Enter Critical Section (acquire lock) -- */
  totalSize = real_getSize();
  /* --- Exit Critical Section (release lock) -- */
  return totalSize;
}

Cela empêche deux fils de même entrer dans la fonction qui contient la variable statique dans le même temps, et à ce que son initialisation se produira au sein d'une section critique.

Autres conseils

Déplacer le calcul dans une fonction d'assistance:

static uint32_t totalSize = calculateTotalSize();

La fonction d'aide sera uniquement invoqué lorsque totalSize s'initialisé.

Un peu en retard, mais pourquoi faites-vous un calcul d'exécution (potentiellement) tout ici? Utilisez les constantes de compilation et vous ne pouvez jamais même avoir des problèmes de filetage:

template<
  typename T1, unsigned N1,
  typename T2, unsigned N2,
  /* ... */
>
struct totalSize {
    static const uint32_t sum = 
        sizeof(T1)*N1
      + sizeof(T2)*N2
      /* ... */
      ;
    static const uint32_t value =
        8*((sum + 7)/8);
};

uint32_t GroupAlloc::getSize() {
    return totalSize<T1,N1,T2,N2,/*...*/>::value;
}

Quelque chose comme:

static uint32_t getSize()
{
    static uint32_t totalSize = 0;
    static bool computed = 0;
    if(computed)
      return totalSize;
    computed = 1;
    // ... go on with your computation

ferait l'affaire. Notez que ce n'est pas thread-safe.

static uint32_t totalSize = 0;    // initialisation performed once only
if ( totalSize == 0 ) {
        totalSize += sizeof(T1)*N1;
        totalSize += sizeof(T2)*N2;
        totalSize += sizeof(T3)*N3;
        totalSize += sizeof(T4)*N4;
        // etc
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top