Pergunta

Eu tenho uma classe com método estático que tem uma variável local estática.Eu quero que a variável a ser calculada/avaliadas de uma vez (a 1ª vez que chamar a função) e para quaisquer subsequentes invocação, que não é avaliada mais.Como fazer isso?Aqui está a minha 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;
    }
};

EDITAR:

Obrigado a todos pela sua pronta ajuda.+1 para todos.Eu escolhi Tyler McHenry a resposta de porque ele não precisa de qualquer comparação, puramente estática função de avaliação.Eu vou precisar deste código, para alocador de forma a evitar outro "se" deve ser melhor.Obrigado novamente!

EDITAR:

gf resposta acabou por ser o melhor, de como ela lida com a atribuição durante o tempo de compilação e salva o programa de thread-safe dor de cabeça e explícitas de inicialização.No entanto, eu respeito o anterior melhor resposta.Vou dar crédito aqui em vez de alterar a marca de escala.Obrigado a todos por ajudar!

Foi útil?

Solução

Fazer outra função estática que faz o cálculo, e usar isso para a inicialização da variável, exemplo:

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

Variáveis estáticas são garantidos para ser inicializado exatamente uma vez (a primeira vez que a função que as contenham, é usado).

Editar: Mas isso é não thread-safe. Esta página explica por que, em grande detalhe.

Para torná-lo thread-safe, não é suficiente para quebrar a inicialização do totalSize (a chamada computeSize) em uma seção crítica, porque variável estática inicialização do compilador "magia", e pode ser que a variável passa a inicialização, a qualquer momento durante a chamada para getSize antes de ser utilizado, mesmo antes de a função da primeira instrução.O que você precisa fazer é impedir que mais de um segmento de mesmo chamar getSize ao mesmo tempo, o que pode ser feito com outro nível de indireção, e.g.

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

Isso impede que duas threads a partir até mesmo de entrar na função que contém a variável estática, ao mesmo tempo, e garantir que a inicialização irá ocorrer dentro de uma seção crítica.

Outras dicas

Mova o cálculo para uma função auxiliar:

static uint32_t totalSize = calculateTotalSize();

A função auxiliar será invocada apenas quando totalSize é inicializado.

Um pouco tarde, mas por que você está fazendo um cálculo de tempo de execução (potencialmente) aqui? Use constantes de tempo de compilação e você nunca pode ter problemas de rosqueamento:

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

Algo como:

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

faria o truque. Observe que não é seguro para threads.

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
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top