4

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?

Simon Linder
  • 3,378
  • 4
  • 32
  • 49
  • Try creating a new project from scratch and see if it happens there as well – shoosh Apr 27 '10 at 10:57
  • Sorry, can't do. As I said it's a really huge project. – Simon Linder Apr 27 '10 at 10:57
  • 1
    I assume the first example was a typo and should have been `AnotherClass* const MyClass::Default_(new AnotherClass(""));` – Andreas Brinck Apr 27 '10 at 10:59
  • 1
    You could still try making a new empty test project with a static member and see if it initializes correctly though... – AshleysBrain Apr 27 '10 at 11:00
  • @Andreas: No DLL @Ashley: Ok, I created a new project similar to the post of sbi and it also works!? – Simon Linder Apr 27 '10 at 11:12
  • 1
    Is the code in a static library? Then you run into problems, if class MyClass (precisely the compilation unit) is not referenced by the depended program. The linker then will not create static initialization code for the variable. – jopa Apr 27 '10 at 13:33

4 Answers4

6

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
  • 4,554
  • 1
  • 19
  • 19
  • It's bad taste to use a pointer in this case. A plain instantiation followed by returning a reference would be much better. After all, isn't a `* const` the semantic equivalent to `&` once you've removed the NULL possibility ? – Matthieu M. Apr 27 '10 at 14:45
  • @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 Apr 27 '10 at 18:04
  • 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. Apr 28 '10 at 06:19
  • 1
    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 Apr 28 '10 at 19:18
4

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

sth
  • 222,467
  • 53
  • 283
  • 367
  • Is this a Visual Studio compiler related problem? Or a general problem? – Simon Linder Apr 27 '10 at 11:19
  • 1
    @Simon: That's a general problem. – sth Apr 27 '10 at 11:42
  • So it can't be my problem here as the Linux developer doesn't have a similar problem... – Simon Linder Apr 27 '10 at 11:45
  • 4
    @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 Apr 27 '10 at 11:51
3

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
  • 66,617
  • 42
  • 165
  • 277
0

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
  • 219,715
  • 46
  • 258
  • 445
  • But in his second example he remembered the `MyClass::` so it's probably just a typo in the question. – Andreas Brinck Apr 27 '10 at 11:00
  • 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 Apr 27 '10 at 11:18
  • @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 Apr 27 '10 at 13:41