如何创建一次评估局部静态变量的静态方法?

时间:2010-03-20 11:56:06

标签: c++ templates static-methods lazy-evaluation static-variables

我有一个静态方法的类,它有一个本地静态变量。我希望计算/评估该变量一次(我第一次调用该函数),并且对于任何后续调用,它不再被评估。怎么做?这是我的班级:

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

编辑:

感谢大家的快速帮助。 +1给大家。我选择了Tyler McHenry的答案,因为它不需要任何比较,纯粹的静态功能评估。我将需要这个代码用于分配器,所以避免另一个“如果”应该更好。再次感谢!

编辑:

gf的答案结果是最好的,因为它在编译时处理赋值并将程序从线程安全的头痛和显式初始化中保存。但是,我尊重以前的最佳答案。我会在这里给予赞誉,而不是更改刻度线。谢谢大家的帮助!

4 个答案:

答案 0 :(得分:4)

创建另一个执行计算的静态函数,并将其用于变量的初始化,例如

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

保证静态变量只被初始化一次(第一次使用包含它们的函数)。

编辑但这是线程安全。 This page explains why in great detail

为了使它成为线程安全的,将totalSize(对computeSize的调用)的初始化包装在一个关键部分是不够的,因为静态变量初始化是“编译魔术”,并且它可以是变量在使用之前的任何时候在getSize调用之前进行初始化,甚至在函数的第一个语句之前。你需要做的是阻止多个线程同时调用getSize,这可以通过另一个间接层来完成,例如。

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

这可以防止两个线程同时进入包含静态变量的函数,并确保其初始化将在关键部分内进行。

答案 1 :(得分:3)

将计算移动到辅助函数中:

static uint32_t totalSize = calculateTotalSize();

只有在初始化totalSize时才会调用辅助函数。

有点晚了,但为什么你在这里进行(潜在的)运行时计算呢?使用编译时常量,你甚至不会遇到任何线程问题:

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

答案 2 :(得分:2)

类似的东西:

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

会做到这一点。请注意,它不是线程安全的。

答案 3 :(得分:2)

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
}