简体   繁体   中英

C++ Initialize Static Array

I am not sure that this is even possible. From all the examples I have seen, the array is defined within the { } brackets, but in my case it is not much possible.

What I am trying to do is keep this in my drawing function to draw multiple circles that slowly increase in size.

What I am getting by using a debugger is the static array is being reset every time the loop hits.

I have also tried something like 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
 }

the static array is being reset every time the loop hits

well yes, your loop explicitly resets the static array.

The minimal change is to just run the initialization loop once:

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
}

but this is pretty ugly, and unnecessarily hard to reason about. Prefer something like

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

There is nothing to be surprised about here. Every time a function is called, all its code is executed from its arguments. The only exception here would be the initialization of a static variable, which is guaranteed to run only once during the lifetime of the program (also thread-safe since C++11). The initialization of a variable only happens during its definition, on the very line you give your variable the name in this context. All the code after that is simply "mutating" your variable to give it the value you wanted to: it is not initialization.

There are two solutions here. Either you use std::call_once with a lambda (see http://en.cppreference.com/w/cpp/thread/call_once ) to make the "initialization" code run only once. Or you somehow fit all that code in one line on the definition of the variable. It might be complicated for a C-style array, but not for a std::array , which can be easily returned from functions and be used to initialize an 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
}

You can split your code and put the array initialization elsewhere:

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

Then, just call that in your function:

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
}

That way, you don't introduce an additional branch in your code, it look much cleaner and it's thread safe.

The other answer is fine, as long as the whole thing doesn't have to be thread-safe.

If the initialization must be thread safe, there's no alternative to shoving everything into the declaration.

However, a helper class can be used to minimize the typing:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM