0

I have a problem with static vars/deque and objects. I am calculating some statistics for a real time data stream - mean, median, skew etc. As this is streaming data I make use of static vars, or in this version static container (deque). I have made several versions and they all exhibit the same problem. Even though I make two instances of the same method, the static deque seems to be shared. I have the following code (not the most efficient but readable):

double Mean(double& lastValue, const int& length)
{
    static std::deque<double> buffer(length);
    double sum = 0.0;

    buffer.pop_back();
    buffer.push_front(lastValue);

    for (int j = 0; j < length; j++) {
        try {
            sum += buffer.at(j);
        }
        catch (const std::out_of_range& oor) {
            std::cerr << "Out of Range error: " << j << " - " << oor.what() << '\n';
        }
    }

    return length != 0 ? sum / length : 0;
}

If I make two instances of this like:

Stats s1, s2;
s1.Mean(streamData, 20);
s2.Mean(streamData, 30);

I get Out Of Range error.

Questions:

  1. What is causing the out_of_range exception?
  2. I might be wrong, but it seems like the static deque is shared between two objects - how is this possible?

Any help appreciated!

CSchulz
  • 10,882
  • 11
  • 60
  • 114
Joerg
  • 63
  • 1
  • 1
  • 4
  • How do you make two or even one instance of a method? – harper Nov 10 '14 at 10:06
  • 1
    A function-static object or variable has one instance per function, not one instance per Stats object. If you want the queue to be shared by all Stats objects, make the queue a static object in the class. – Erik Alapää Nov 10 '14 at 10:06
  • @Erik OK, so it's one instance per function, not per object. Now I understand why I get the out_of_range exception. Any suggestion how this can be solved, except for passing a deque to each function? – Joerg Nov 10 '14 at 10:16
  • You can traverse the queue using iterators, instead of assuming that the length is correct. Even better, perhaps use STL accumulate to compute the sum. http://www.cplusplus.com/reference/numeric/accumulate/ – Erik Alapää Nov 10 '14 at 10:22
  • @Erik That's some of the things I have tried. Another way is to use sum -= buffer.back(), sum += buffer.front(). However, what I want to avoid is the sharing of the static deque, so I don't get the out_of_range error. – Joerg Nov 10 '14 at 10:27
  • But if you want one deque per Stats object, just make the deque an instance variable/instance object. Am I missing something? – Erik Alapää Nov 10 '14 at 10:35

1 Answers1

1

on 2: a static variable in C has a lifetime that expands over the lifetime of the program. Therefore, there is only one instance of your buffer variable when the program is running.

on 1: so in your program: you first construct a deque buffer of size 20 using the s1 object, then you try to use it for a size of 30 using the s2 object. This causes the out of range error on the 20-29 range as the variable is the one statically created.

Using static variables inside code is generally not a good idea.

Edit:

What you really want is to have a deque member variable in your Stats class.

 class Stats {
 private:
  std::deque<double> buffer;
  ...

you access this variable (per object) in your Mean function. (do not forget to initialise it in the constructor of Stats).

If you need to resize the deque, you can use:

buffer.resize(length);
chrphb
  • 542
  • 5
  • 5
  • One solution I have is: double Mean(double& lastValue, const int& length, std::deque& buffer)? Any other solution? – Joerg Nov 10 '14 at 10:41
  • the usual way of doing it is to use a member class attribute. see my edit. – chrphb Nov 10 '14 at 10:52