0

I have a base class with a static pointer member. When I assign that static pointer member in a derived class, that static member appears NULL when referenced from the methods of the base class.

This is not the behavior I expect. Shouldn't the static pointer member still be assigned regardless of where it is accessed from? Am I wrong about the expected behavior?

The static member is a pointer to a base class. I realize that what I am trying to achieve is probably best accomplished by static polymorphism using templates ( Static polymorphism definition and implementation ) but I still do not understand why in this scenario the pointer member itself is NULL.

Edit: the behavior is NOT demonstrated in this SSCE. What bugs or common errors would cause the behavior I describe? My actual production scenario is significantly more complicated than this, but the structure is almost exactly the same. I am literally in the VS2010 debugger observing Base::staticMember == not null, then call to Base::staticMethod(), and inside Base::staticMethod(), Base::staticMember is null. I am baffled.

#include <iostream>

class Base {
public:
    static Base *staticMember;

    static void baseMethod();
};

Base *Base::staticMember = NULL;

class Derived : public Base {
public:
    void derivedMethod();
};

void Base::baseMethod() {
    // here staticMember == NULL, the unexpected behavior
    if(staticMember == NULL) {
        std::cout << "NULL";
    } else {
        std::cout << "NOT NULL";
    }
};

void Derived::derivedMethod() {
    staticMember = new Derived();
}

int main(int argc, void *argv[]) {
    Derived *derived = new Derived();
    derived->derivedMethod();
    Base::baseMethod();
}
Community
  • 1
  • 1
taz
  • 1,506
  • 3
  • 15
  • 26
  • 2
    I don't believe you're interpreting the problem properly. How do you know the pointer is NULL? – Mark Ransom Nov 30 '12 at 02:07
  • 1
    The code shouldn't even compile, you have several errors. – Jesse Good Nov 30 '12 at 02:09
  • I know, sorry I made the mistake of just typing up an example to illustrate my point. I have edited my post to include an SSCE. – taz Nov 30 '12 at 02:13
  • Not sure a SSCE that doesn't produce the problem is really a SSCE... you'll probably figure out the problem if you keep working at really reproducing it. If I had to guess, I'd guess you are hiding the staticMember. http://stackoverflow.com/questions/5189572/why-c-has-the-feature-of-overloading-and-name-hiding – Zero Nov 30 '12 at 02:22
  • I hate SSCEs because they generally don't help me. Of course the problem isn't reproduced in a toy example. The error is a bug somewhere in my incredibly complicated actual code. First I need to identify that I am not wrong about the expected behavior, and then identify potential causes of the bug. The methods are virtual and the staticMember is protected and not hidden. – taz Nov 30 '12 at 02:24
  • If your SSCE is working as you expect, doesn't that show what the expected behaviour is? Good luck with the production code... I often finding making the SSCE more complicated (more like prod) until it breaks is the easiest way of finding the error. I usually come to this conclusion after staring at my prod code for several hours failing to find the bug. – Zero Nov 30 '12 at 02:27
  • Thanks...unfortunately that is not feasible in this scenario. I have already spent way more than several hours trying to figure this out and the actual code represents months of work. At least I know I was correct about the expected behavior. The base static member pointer simply changes to NULL in the memory when the base static method is invoked. There is actually an intermediate class that carries an instance of the base class and invokes the static method, but I don't see what difference that would make. When the base static method returns to the calling point, it no longer reads as NULL. – taz Nov 30 '12 at 02:30
  • If you can't make a SSCE showing your problem, it probably means the problem is not exactly what you think it is. – aschepler Nov 30 '12 at 02:35
  • @aschepler and the actual code is not something I can post, hence my dislike of SSCEs. I have the static member in a watch. Paused in Base::staticMethod(), it is NULL. Double-clicking on the call stack to go up one to the calling point, the value changes to not null in the watch window. I can go back and forth to the different execution contexts and the static member in the watch window changes to NULL and back. This is the unexpected behavior. I don't know how to duplicate it. What causes this to happen? – taz Nov 30 '12 at 02:39
  • It sounds like your debugger's watch window is getting confused about exactly what it's supposed to watch. Throwing in questions about the debugger adds another layer for potential confusion, and this doesn't necessarily mean the actual C++ code has any unexpected behavior. – aschepler Nov 30 '12 at 02:43
  • @aschepler The code has a conditional for the NULL, and the value is actually read as NULL. I have been bitten by the debugger before so I checked for this before posting. – taz Nov 30 '12 at 02:44
  • Does `&staticMember` change too? Maybe you have more than one variable with the same identifier, and it's a hiding/scope issue. – aschepler Nov 30 '12 at 02:46
  • No. When viewed from `Base::staticMethod()`, `Base::staticPointerMember` has a different address than when viewed from the calling point, and the different address has a NULL value. How is that possible? – taz Nov 30 '12 at 03:07
  • To exapand on @aschepler, try logging `cerr << &staticMember` in each function that uses it and see if the address changes. – Zero Nov 30 '12 at 03:08
  • @Zero to be specific, I just did that, at @aschepler's suggestion, and once execution hits `Base::staticMethod()`, the address of `Base::staticMember` is different. I am once again baffled. Thank all of you for your help. – taz Nov 30 '12 at 03:10
  • 1
    If the address is different, you are accidentally declaring another variable names `staticMember`. In the derived class you are setting one `staticMember`. This mistake often occurs when a variable has the same name in the child class as in the derived class. You could improve your encapsulation by making `staticMember` private in the base class, and provide a protected `SetStaticMember` function on the base class. The derived class calls `SetStaticMember` instead of dealing directly with the variable. – Zero Nov 30 '12 at 05:15
  • I absolutely swear that I am not. The actual code has `staticMember` declared in an `AbstractBase` parent of `Base`. I actually tried putting `setStaticMember()` in `AbstractBase`, which seemed to work, but I got the _same behavior_ from `Base::staticMethod()`. I actually have a function that calls `Derived::setStaticMember()`, then `OtherClass::someFunc()`, which then calls `Base::staticMethod()`, in which `Base::staticMember` is somehow at a different address and is `NULL`. I realize that accidentally using two variables seems like the only possible answer, but I don't see that anywhere. – taz Nov 30 '12 at 05:42

4 Answers4

2

Your compiler is clearly the problem here, and I'm not surprised since it allows both

int main(int argc, void *argv[])

and

Derived derived = new Derived();

For example, see the result in ideone. The static member should clearly not be null.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
1

No repro on a fixed up and simplified version of your code:

#include <iostream>
#include <iomanip>

struct Base {
    static Base* staticMember;

    static void baseMethod();
};

Base* Base::staticMember;

void Base::baseMethod() {
    std::cout << std::boolalpha << (staticMember == nullptr) << std::endl;
}

struct Derived : Base {
    void derivedMethod();
};

void Derived::derivedMethod() {
    staticMember = this;
}

int main() {
    Derived derived;
    derived.derivedMethod();

    Base::baseMethod();
}

Prints "false".

Always give a Short, Self Contained, Correct (Compilable), Example, or your question is meaningless.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
0

As mentioned, the SSCE works, but your prod code doesn't. If you make a change like:

void Derived::derivedMethod() 
{
    Base::staticMember = new Derived();
}

this explicitly tells the compiler what variable you are talking about, and may throw up cases where you are accidentally hiding the base member.

(I think gcc might require Base::staticMember - perhaps not in this exact case)

Zero
  • 11,593
  • 9
  • 52
  • 70
  • I have tried this. I have tried using `Base::staticMember`, `Derived::staticMember`, and just `staticMember`, all with the same results. – taz Nov 30 '12 at 03:09
  • Then apart from logging `&staticMember` I'm out of ideas, except for the really annoying and patronizing "try to simplify you incredibly complex prod code into smaller logical chunks to make it easier to isolate problems". (I hate receiving that advice, but there's been more than a few times I've lost the forest for the trees). – Zero Nov 30 '12 at 03:11
0

Maybe you have accidentally declared class Derived { static Base *staticMember; };

So you have two staticMembers floating around.

This is why an SSCE is useful, to keep people like me from making unfounded guesses.

brian beuning
  • 2,836
  • 18
  • 22