views:

422

answers:

4

Hi, I wrote a program out, which was all in one file, and the methods were forward declared in a header. The program initially worked perfectly when it was in one file. But when I separated the program, I kept getting random occurrences for the destructor of one of the classes which was declared in the header file.

I have a static variable in my header to count the number of objects of a particular class. Whenever I construct the object I increment this variable. Then in my destructor I subtract 1 from that variable, check if it's 0 (meaning it's the last object) and do something. The value seems to be off sometimes, I'm not sure why. I do have random calls in my application but I don't see why that would effect what I have described above, thanks. Any help or insight is appreciated!

[Update]: have a base class, which contains the destructor.. which is implemented in the header, then I have two derived classes, which in their constructor increment the static var.. so what can I do?

What I am trying to do is the following: In my header I have this:

class A {
public:
    virtual ~A() {
        count --;
        if (count == 0) { /* this is the last one, do something */ }
    }

class B : public A {
public:
    B();
}

Then in Class B I have

B::B() { 
    count++;
}

Where can I define count so I don't get misleading counts? Thanks.

A: 

Can you elaborate what you mean by the "value seems to be off"? Do you get too many constructions? Not enough destructions? If you get too many constructions and not enough destructions, it would not have anything to do with the statics.

Also, what do you mean by a static variable? Do you mean a static member field or an actual static variable ?

If you declare just a static variable in the header (which I doubt that you do), then each C file that includes that header would have a separate instance of that variable (since static before a global variable means that it is limited to that object file).

Uri
I do have the static variable in my header, where else can I put it because my destructor is defined in header and it uses that variable, thanks.
BobS
@BobS, is the static variable part of the class, or outside the class's block? You probably want it inside your class. Also, you need to define (?) it in one of your .cpp files so it'll be exported once.
strager
I have a base class, which contains the destructor.. which is implemented in the header, then I have two derived classes, which in their constructor increment the static var.. so what can I do?
BobS
@BobS, please paste your code (or relevent parts) in your original question so we can see exactly what you're doing. Thanks.
strager
@Bobs, I second strager, can you post the code or at least the code for the class? we are trying to determine if your static is written as a member or as a global variable. These have different semantics in C++, as my answer indicated.
Uri
+1  A: 

Where is your static variable defined? Perhaps you are accidentally defining it in the header file, and the inlining is confusing things (and the compiler doesn't catch the multiple definitions, which would be odd, but you never know).

Make sure a class-static variable is defined in exactly one translation unit. You define it like this:

int MyClass::static_var;

This is also the place you put the initializer, if any.

coppro
Hi, in my header I have a destructor which will need to call static_var. But I also need to call static_var in my constructor for my two derived classes, so where can I place this line?
BobS
A: 
class A {
public:
    virtual ~A() {
        count --;
        if (count == 0) { // this is the last one, do something }
    }
protected:
    static int count;
};

class B : public A{
public:
B();
};

And then, in one and only one of your source files you need to put the following. It should go in the source file that contains the code for class A.

int A::count(0);

You need to do this, because the header file declared that there was going to be a variable named count, but didn't allocate any storage for it. If you didn't put it in a source file, the linker would complain that it wasn't found.

Mark Ransom
Still not correct.
Martin York
@Martin, of course you are correct. I'll upvote your answer.
Mark Ransom
@Mark R: Thanks.
Martin York
+4  A: 

You must define the constructor in A (all of them) to increment the count.

Note unless you define them the compiler automatically generate the following four methods:

  • Default Constructor (if no other constructor is defined)
  • Default Destructor
  • Copy Constructor
  • Assignment operator

The following code overrides the compiler defaults so that you should get an accurate count.

 class A
 {
    static int count;

    public:
        A()   // Default constructor.
        {
            ++count;
        }
        A(A const& copy)  // Copy constructor/
        {                 // Note If you do not define it the compiler
            ++count;      // will automatically do it for you
        }
        virtual ~A()
        {
            --count;
            if (count == 0)
            {  // PLOP
            }
        }
        // A& operator=(A const& copy)
        // do not need to override this as object has
        // already been created and accounted for.
};

//// In source file:

int A::count = 0;
Martin York