Domanda

Ho una classe con metodo statico che ha una variabile statica locale. Voglio che variabili da calcolare / valutate una volta (la prima volta che io chiamo la funzione) e per ogni invocazione successiva, non viene valutata più. Come farlo? Ecco la mia 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:

Grazie a tutti per il vostro aiuto tempestivo. +1 a tutti. Ho scelto la risposta di Tyler McHenry, perché non ha bisogno di alcun confronto, puramente valutazione della funzione statica. Ho bisogno di questo codice per allocatore evitando così un altro "se" dovrebbe essere migliore. Grazie ancora!

EDIT:

La risposta di GF si è rivelata la migliore in quanto si occupa di assegnazione durante la fase di compilazione e salva il programma di mal di testa thread-safe e l'inizializzazione esplicita. Tuttavia, io rispetto la migliore risposta precedente. Darò credito qui invece di cambiare il segno di spunta. Grazie a tutti per l'aiuto!

È stato utile?

Soluzione

nuova funzione statica che fa il calcolo, e l'uso che per l'inizializzazione della variabile, per esempio.

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;
}

Le variabili statiche sono garantiti per essere inizializzato esattamente una volta (la prima volta che si utilizza la funzione che li contiene).

Modifica Ma questo è non thread-safe. Questa pagina spiega il motivo per cui in grande dettaglio .

Per rendere thread-safe, non è sufficiente per avvolgere l'inizializzazione totalSize (chiamata a computeSize) in una sezione critica, per inizializzazione variabile statica è "compilatore magico", e può essere che la variabile di subisce inizializzazione in qualsiasi momento durante la chiamata a getSize prima di essere utilizzato, prima ancora che prima istruzione della funzione. Quello che dovete fare è evitare che più di un filo da anche chiamando getSize, allo stesso tempo, che può essere realizzato con un altro livello di indirezione, per es.

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;
}

Questo impedisce due fili da entrare anche la funzione che contiene la variabile statica, allo stesso tempo, e assicurare che la sua inizializzazione avverrà entro una sezione critica.

Altri suggerimenti

Sposta il calcolo in una funzione di supporto:

static uint32_t totalSize = calculateTotalSize();

La funzione di supporto verrà richiamato solo quando totalSize viene inizializzato.

Un po 'in ritardo, ma perché stai facendo una (potenzialmente) Calcolo runtime qui a tutti? Utilizzare costanti in fase di compilazione e non si può mai nemmeno avere problemi di threading:

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;
}

Qualcosa di simile:

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

farebbe il trucco. Si noti che non è 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
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top