-2

following compiles fine with g++:

struct acounter {

  long static counter;

  void static create() {  //reset or create the counter
    counter=0;
  }

  void static count() {   //the counter changes its internal value.
    counter=counter + 1;
  }   

};


int main(int   argc,  char *argv[] ){    //compiles and executes!
  //do some random stuff...
  return 0;
}

The problem is: as soon as I add "acounter::create();" or "acounter::count();" to the main loop, I get an error:

undefined reference to `acounter::counter'

But I defined "counter" and even initialize it. What is the problem?

(P.S. I can only use static functions as I have to deal with callbacks later - the idea is to use the whole struct only on its global scope without creating instances.)

Kenobi
  • 425
  • 1
  • 4
  • 19

2 Answers2

2

Static class members need to be defined as well as declared. While we're at it, we can initialize the static member to the right value, so no more need for "create" - but we could feasibly have a "reset" logic.

Also, if you're actually exposing the logic via static functions, the counter itself should be private.

Finally, as a matter of style, the static keyword is usually placed before the type name. It's a matter of taste, but it's a rather important attribute and one should be able to quickly tell static and non-static members apart when looking at a class definition.

struct acounter
{
private:
  static long counter;
public:
  static void reset() { counter = 0; }
  static void count() { ++counter; }
};

long acounter::counter = 0;   // definition and initial value

int main()
{
  acounter::count();
}
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • I thought it was common practice, rather than a matter of taste, to place keywords like `static` first. – Chiffa Oct 13 '13 at 11:47
  • @Chiffa: Well, I'd say so, too, but I can't speak for everyone. I think it's definitely more readable, and I've never seen anything else in "real" codebases... – Kerrek SB Oct 13 '13 at 11:48
  • Thanks, perfect answer - that one extra line did it. – Kenobi Oct 13 '13 at 12:02
  • @Kenobi: Yep, it does. Just be sure to have only *one* definition in your program (i.e. put that line into a single translation unit only). – Kerrek SB Oct 13 '13 at 12:03
0

Put this into *.cpp:

long acounter::counter;

NOTE: You might want to initialize it as well, for example:

long acounter::counter = 0;

static, but non-const data members should be defined outside of the class/struct definition and inside the namespace enclosing the class/struct. The usual practice is to define it in the translation unit (*.cpp) because it is considered to be an implementation detail.

Extract from section 9.4.2 of the C++ Standard:

The definition for a static data member shall appear in a namespace scope enclosing the member’s class definition.

There is also another way. Only static and const integral types can be declared and defined at the same time (inside class/struct definition):

class Example {
public:
  static const long x = 101;
};

in this case you don't need to add x definition because it is already defined inside the class/struct definition. In your case, long is integral type, but not const so you cannot opt to this approach.

Alexander Shukaev
  • 16,674
  • 8
  • 70
  • 85