views:

262

answers:

4

Hi all,

I've got a strange problem with a static variable that is obviously not initialized as it should be.
I have a huge project that runs with Windows and Linux. As the Linux developer doesn't have this problem I would suggest that this is some kind of wired Visual Studio stuff.

Header file

class MyClass
{
    // some other stuff here
    ...
    private:
        static AnotherClass* const Default_;
};


CPP file

AnotherClass* const MyClass::Default_(new AnotherClass(""));
MyClass(AnotherClass* const var)
{
    assert(Default_);
    ...
}

Problem is that Default_is always NULL. I also tried a breakpoint at the initialization of that variable but I cannot catch it.

There is a similar problem in another class.
CPP file

std::string const MyClass::MyString_ ("someText");
MyClass::MyClass()
{
    assert(MyString_ != "");
    ...
}

In this case MyString_is always empty. So again not initialized.
Does anyone have an idea about that? Is this a Visual Studio settings problem?
Cheers Simon

Edit:
I also came across the static initialization fiasco. But I'm not sure if that could be the problem because there are no problems with the Linux compiler. Shouldn't the compiler react the same way in this case?

A: 

Works On My Machine(TM):

#include <iostream>
#include <cassert>

class AnotherClass
{
public:
    AnotherClass(const char*) {}
};

class MyClass
{
public:
    MyClass(AnotherClass* const var);
private:
    static AnotherClass* const Default_;
};

AnotherClass* const MyClass::Default_(new AnotherClass(""));

MyClass::MyClass(AnotherClass* const var)
{
    assert(Default_);
    std::cout << "Worked!\n";
}

int main()
{
    MyClass tester(NULL);
    return 0;
}

I suppose the problem is that MyClass::MyClass() is called as another static variable's constructor. The initialization of static variables doesn't always occur in the order you would like it to.

sbi
But in his second example he remembered the `MyClass::` so it's probably just a typo in the question.
Andreas Brinck
Yes it should and it is, just a typo, but thank you.
Simon Linder
Your example also works for me.
Simon Linder
You mentioned that the call may be within another static variables's constructor. I still have to check this. But shouldn't then be the same problem with the Linux compiler?
Simon Linder
I checked the whole stack trace and cannot find anything static...
Simon Linder
@Simon: If that's a static initialization issue, then the result is _undefined_. That means it might work in one case, but wouldn't in another. If you don't think this is a static initialization issue, then the only thing I can think of is to make a copy of the code, and piece by piece removing some of it, so that the problem still occurs, until you're down to a small example that reproduces the issue. usually the problem is found that way. If not, post it here, when it's small enough, so that others can have a look at it.
sbi
+2  A: 

In case this happens while initializing some other static variables you might be seeing the static initialization fiasco.

sth
Is this a Visual Studio compiler related problem? Or a general problem?
Simon Linder
@Simon: That's a general problem.
sth
So it can't be my problem here as the Linux developer doesn't have a similar problem...
Simon Linder
@Simon: Basically if you have different compilation units/object files it is not guaranteed that they are initialized in a particular order. So if static variables in one object file are initialized first and they try to use other static variables that have not yet been initialized there will be problems. The order is undefined, so it might or might not "work" with another compiler and this might change once you add files to the project or change something else. Since the init order is basically random the problem might very well be there also if it doesn't show up in some particular build.
sth
+4  A: 

I suggest you use static member function with static variable and not static variable itself:

class MyClass
{
    // some other stuff here
    ...
    private:
        static AnotherClass* const getAnotherClass();
};

AnotherClass *const MyClass::getAnotherClass()
{
    static AnotherClass *const p = new AnotherClass("");
    return(p);
}

The standard guarantees that p is initialized once when the function is called for the first time, so you will always get properly initialized object (unless you've already exhausted memory or you constructor threw).

Please note - this may or may not be thread safe (depends on your compiler really).

And yet another note - now you have to live with "memory leak" as it is really next to impossible to decide when to destroy the object and you have NO WAY to reset p to NULL.

Tomek
Matthieu M.
@Matthieu: I am just following the code given. For your comment - you are probably right but it really depends on what AnotherClass does (it may for example eat all the space in your data segment so there is nothing left for other globals).
Tomek
@Tomek: I agree that it may be necessary to use the *heap* in order not to saturate the data segment or the stack (I kind of wish for `Go` here...) however it should be reserved, I think, to special situations (big objects) and postponed until necessary.
Matthieu M.
One more note here on static AnotherClass versus static pointer to AnotherClass: when you use pointer, the object is very likely to remain for the program lifetime and its destructor probably will not be called unless to take care of that. This may be a problem when the object holds system resource which you must free manually.For the static object the destructor WILL be called but you have no idea and no control when it happens and this may cause you static destruction order fiasco.
Tomek
+2  A: 

Shouldn't the compiler react the same way in this case?

No. As I understand it, the initialization order of individual compilation units is UNDEFINED. So the Linux developer just got lucky. Today. Tomorrow, who knows?

Roddy