3

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
 }
7
  • 3
    In what context is the code? Are both the code and the static array inside a function, or is the static in the namespace scope? Please give a minimal reproducible example Commented Feb 6, 2017 at 14:19
  • @KABoissonneault added the example. From a timer that function is called every 5 seconds. Commented Feb 6, 2017 at 14:23
  • 1
    The for loop will execute every time you call the function. Commented Feb 6, 2017 at 14:23
  • @JohnnyMopp because this array is not needed on a larger scope (global the next option?), is there anyway to fill the array only once? I thought normally you can do that, like static int = 5; Commented Feb 6, 2017 at 14:25
  • 1
    static int s_something = 5; only works because it's initialization, you can't reinitialize and so the value won't "switch back" if it's been re defined somewhere else. Commented Feb 6, 2017 at 14:27

4 Answers 4

4

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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
}

Comments

1

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

7 Comments

Nice, that solution works. If my program (game) wasn't already bogged down with classes, I would opt for the latter.
Might also want to use the facilities in <random> if you want better/portable random number generation
@EvanCarslake: You aren't creating new classes because you have used up your arbitrary quota of classes per project? Seriously?
Note that the first solution is not thread-safe. Also, @EvanCarslake, I don't think there is such a thing as too many classes. Classes in C++ can be "zero overhead" abstractions, meaning that they are free tools for you to use, without pessimizing the execution of your program. If a class can help you hide some complex logic in a simple interface, then you should always do so.
@llnspectable well, really what I meant is that my main drawing function is pretty enormous and these specific draw parts I would like compact within. For example, this is an animation that changes on every different level. I guess I could make a class to handle all of that...
|
1

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.