views:

469

answers:

4

For debugging, I would like to add some counter variables to my class. But it would be nice to do it without changing the header to cause much recompiling.

If Ive understood the keyword correctly, the following two snippets would be quite identical. Assuming of course that there is only one instance.

class FooA
{
public:
    FooA() : count(0) {}
    ~FooA() {}

    void update()
    {
     ++count;
    }

private:
    int count;
};

vs.

class FooB
{
public:
    FooB() {}
    ~FooB() {}

    void update()
    {
     static int count = 0;
     ++count;
    }
};

In FooA, count can be accessed anywhere within the class, and also bloats the header, as the variable should be removed when not needed anymore.

In FooB, the variable is only visible within the one function where it exists. Easy to remove later. The only drawback I can think of is the fact that FooB's count is shared among all instances of the class, but thats not a problem in my case.

  • Is this correct use of the keyword? I assume that once count is created in FooB, it stays created and is not re-initialized to zero every call to update.
  • Are there any other caveats or headsup I should be aware of?

Edit: After being notified that this would cause problems in multithreaded environments, I clarify that my codebase is singlethreaded.

+1  A: 

The major problems with static variables occur when they are used together with multi-threading. If your app is single-threaded, what you are doing is quite correct.

anon
+3  A: 

Your assumptions about static function variables are correct. If you access this from multiple threads, it may not be correct. Consider using InterlockedIncrement().

jeffamaphone
+1  A: 

What I usually do in this situation is to put count in a anonymous namespace in the source file for the class. This means that you can add/remove the variable at will, it can can used anywhere in the file, and there is no chance of a name conflict. It does have the drawback that it can only be used in functions in the source file, not inlined functions in the header file, but I think that is what you want.

In file FooC.cpp

namespace {
int count=0;
}

void FooC::update()
{
    ++count;
}
KeithB
Why do you add it to a namespace? And can you really add/remove it at will? If I delete the namespace definition there, wouldnt the ++count; line cause compile errors?
mizipzor
+1  A: 

What you really want, for your long term C++ toolbox is a threadsafe, general purpose debug counters class that allows you to drop it in anywhere and use it, and be accessible from anywhere else to print it. If your code is performance sensitive, you probably want it to automatically do nothing in non-debug builds.

The interface for such a class would probably look like:

class Counters {
public:
  // Counters singleton request pattern.
  // Counters::get()["my-counter"]++;
  static Counters& get() {
    if (!_counters) _counters = new Counters();
  }

  // Bad idea if you want to deal with multithreaded things.
  // If you do, either provide an Increment(int inc_by); function instead of this,
  // or return some sort of atomic counter instead of an int.
  int& operator[](const string& key) {
    if (__DEBUG__) {
      return _counter_map.operator[](key);
    } else {
      return _bogus;
    }
  }

  // you have to deal with exposing iteration support.

private:
  Counters() {}

  // Kill copy and operator=
  void Counters(const Counters&);
  Counters& operator=(const Counters&);

  // Singleton member.
  static Counters* _counters;

  // Map to store the counters.
  std::map<string, int> _counter_map;

  // Bogus counter for opt builds.
  int _bogus;
};

Once you have this, you can drop it in at will wherever you want in your .cpp file by calling:

void Foo::update() {
  // Leave this in permanently, it will automatically get killed in OPT.
  Counters::get()["update-counter"]++;
}

And in your main, if you have built in iteration support, you do:

int main(...) {
  ...
  for (Counters::const_iterator i = Counters::get().begin(); i != Countes::get().end(); ++i) {
    cout << i.first << ": " << i.second;
  }
  ...
}

Creating the counters class is somewhat heavy weight, but if you are doing a bunch of cpp coding, you may find it useful to write once and then be able to just link it in as part of any lib.

Roosh