C++初始化静态数组

3
我不确定这是否可行。从我看到的所有示例中,数组都在{ }括号内定义,但在我的情况下可能不太可能。
我正在尝试将此保留在我的绘图函数中,以绘制多个缓慢增大的圆。
使用调试器得到的结果是,每次循环命中时,静态数组都会被重置。
我还尝试了类似于static Rect rc[5] = {}的东西。
void fun_called_every_five_seconds() {
     static Rect rc[5];

     for (int i = 0; i < count; i++) {
         int x = rand()%400;
         int y = rand()%400;
         int r = rand()%200;
         rc[i] = Rect (x,y,r,r);
     }

     rc[0].X += 50;


     // I check value of rc[0].X right here
 }

3
代码所处的上下文是什么?代码和“static”数组是否都在函数内部,还是"static"在命名空间作用域内?请提供一个 MCVE。 - KABoissonneault
1
for 循环将在每次调用函数时执行。 - 001
@JohnnyMopp 因为这个数组不需要在更大的范围(全局,下一个选项?)中使用,有没有办法只填充一次数组?我认为通常可以这样做,例如 static int = 5; - Evan Carslake
看起来你正在尝试使用单例模式实现单一初始化点。目前,代码没有检查单例rc是否已经被初始化,导致每次函数调用都会重置它。 - RomanK
1
static int s_something = 5; 只有在初始化时才能工作,您无法重新初始化,因此如果它已在其他地方重新定义,则值不会“切换回来”。 - George
显示剩余2条评论
4个回答

4
你可以将代码分割并将数组初始化放在其他地方:
auto make_rect_array() {
    std::array<Rect, 5> rc;

    for (int i = 0; i < count; i++) {
        int x = rand()%400; // you may want better random
        int y = rand()%400;
        int r = rand()%200;

        rc[i] = Rect (x,y,r,r);
    }

    return rc;
}

然后,在您的函数中调用它:
void fun_called_every_five_seconds() {
    static auto rc = make_rect_array();

    rc[0].X += 50;
    // I check value of rc[0].X right here
}

那样做,你就不会在代码中引入额外的分支,代码看起来更加简洁,且线程安全。

2
这里没有什么好惊讶的。每次调用函数时,都会从其参数执行所有代码。 唯一的例外是static变量的初始化,在程序生命周期中保证只运行一次(自C++11以来也支持线程安全)。 变量的初始化仅在其定义期间发生,在您在此上下文中为变量命名的那一行上。之后的所有代码都只是“变异”您的变量,以赋予它您想要的值:这不是初始化。
这里有两个解决方案。要么使用带有lambda的std::call_once(请参见http://en.cppreference.com/w/cpp/thread/call_once),使“初始化”代码仅运行一次。 要么在变量的定义中以一行代码的方式适应所有代码。对于C风格数组可能很复杂,但对于std::array则不然,可以轻松地从函数返回并用于初始化std::array
std::array<Rect, 5> initialize_rc() {
   std::array<Rect, 5> rc;

   for (int i = 0; i < count; i++) {
       int x = rand()%400;
       int y = rand()%400;
       int r = rand()%200;
       rc[i] = Rect (x,y,r,r);
   }

   return rc;
}

void for_fun_called_every_five_seconds() {
   static std::array<Rect, 5> rc = initialize_rc();

   rc[0].X += 50;

   // I check value of rc[0].X right here
}

1

每次循环命中时,静态数组都会被重置。

是的,你的循环明确地重置了静态数组。

最小的更改就是只运行初始化循环一次:

void for_fun_called_every_five_seconds() {
    static Rect rc[5];
    static bool init = false;
    if (!init) { // this only happens once
        init = true;
        for (int i = 0; i < count; i++) {
            int x = rand()%400;
            int y = rand()%400;
            int r = rand()%200;
            rc[i] = Rect (x,y,r,r);
        }
    }

    rc[0].X += 50;

    // I check value of rc[0].X right here
}

但这很丑陋,而且难以理解。建议使用类似以下的方式:
class Circles {
    Rect rc[5];
public:
    Circles() {
        for (int i = 0; i < count; i++) {
            int x = rand()%400;
            int y = rand()%400;
            int r = rand()%200;
            rc[i] = Rect (x,y,r,r);
        }
    }
    void for_fun_called_every_five_seconds() {
        // should this also be in a loop,
        // ie. each rc[i] gets increased?
        rc[0].X += 50;
        // I check value of rc[0].X right here
    }
};

1
不错,这个解决方案很有效。如果我的程序(游戏)还没有被各种类拖慢的话,我会选择后者。 - Evan Carslake
如果您想要更好/可移植的随机数生成,也可以使用 <random> 中提供的功能。 - NathanOliver
1
@EvanCarslake:你不是因为项目中已经用完了类的任意配额而不再创建新类吧?说真的? - IInspectable
请注意,第一个解决方案不是线程安全的。此外,@EvanCarslake,我认为没有太多的类这种事情。在C++中,类可以是“零开销”抽象,这意味着它们是免费的工具,供您使用,而不会使程序的执行变慢。如果一个类可以帮助您在简单的接口中隐藏一些复杂的逻辑,那么您应该始终这样做。 - KABoissonneault
将事物分解成小类不会使您的“主绘图函数”变得更大,而是会使其变得更小。您可能只需要将更多的东西分解为简单的函数或类。 - Useless
显示剩余2条评论

1
另一个答案很好,只要整个程序不需要线程安全。
如果初始化必须是线程安全的,那么将所有内容塞入声明中是没有替代方案的。
然而,可以使用辅助类来最小化输入。
class RandomRect : public Rect {

public:
    RandomRect() : RandomRect(rand() % 400, rand() % 400, rand % 200) {}
    RandomRect(int x, int y, int r) : Rect(x, y, r, r) {}
};

// ... Then, initialize the static array as follows:

static Rect rc[5]={RandomRect(), RandomRect(), RandomRect(),
                   RandomRect(), RandomRect()};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接