Static object doesn't call its constructor?

Dec 21, 2011 at 11:26pm
I'm resizing a std::vector in the constructor of a class, and when I later try to access it the std::vector is empty. The following code reproduces the problem:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <vector>

class Foo
{
public:

    Foo();

    static void Bar();

private:

    static Foo foo;

    static std::vector <short> shorts;
};

std::vector <short> Foo::shorts;

Foo::Foo()
{
    shorts.resize(5, 0);
}

void Foo::Bar()
{
    std::cout << shorts.size();
}

int main()
{
    Foo::Bar();
}


However, when creating the Foo object in the int main() function, the std::vector is resized. Does this mean the constructor of a static object doesn't get called on creation?

Any help would be appreciated, thanks.

EDIT: I've experimented and found out that the constructor doesn't get called. Does anyone know why this is?
Last edited on Dec 21, 2011 at 11:31pm
Dec 21, 2011 at 11:32pm
You aren't creating a Foo object in main(), you're just calling Bar().
Dec 21, 2011 at 11:35pm
Oh, so member objects' constructors don't get called?
Dec 21, 2011 at 11:49pm
Huh? The constructor is called when you create a Foo object, which you aren't doing. You're calling Bar without an object, which is only possible because it's a static member function.
As for static members, they're created when the program starts, which also means their constructor is called (vector<short>'s default constructor in this case).
Dec 21, 2011 at 11:55pm
When I said "when creating the Foo object in the int main() function, the std::vector is resized," I meant that if I were to create the Foo object in int main() instead of the class Foo, the std::vector would be resized. I was wondering why the Foo object's constructor wasn't being called. How would I call a member object's constructor, if possible?
Last edited on Dec 21, 2011 at 11:55pm
Dec 21, 2011 at 11:56pm
What Athar is trying to say is what I said to someone earlier. Classes are variables. You treat them just like any other variable.

Example:
1
2
3
4
5
6
7
int main(){
    int a, b; // Declare the variables a and b
    a = 1; // Define the variable a
    b = 1; // Define the variable b

    a += b; // Operate on the variables a and b
}


Now with classes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Foo{
    static Foo foo;
    static std::vector<short> shorts;

public:
    Foo();
    static void Bar();
};

std::vector<short> Foo::shorts;

Foo::Foo(){
    shorts.resize(5, 0);
}

void Foo::Bar(){
    std::cout << shorts.size();
}

int main(){
    Foo foos; // Declare a variable
    foos = new Foo; // Define a variable

    Foo::Bar(); // Operate on a variable
    delete foos; // Undefine a variable
    return 0;
}
Dec 22, 2011 at 12:02am
I understand that objects are variables, but why don't their constructors get called if they're declared in a class and not in int main() or in a function int main() calls?
Dec 22, 2011 at 12:05am
They do, but you never declared an instance of the object. You have to actually go through the process of creating an instance of the object that you're attempting to manipulate, and in your example you aren't doing that. Look at my examples, specifically the comments that I put in, and compare the two examples.
Dec 22, 2011 at 12:12am
"foo" isn't an instance of Foo? Both examples have a line which declares an instance of the object, don't they? "static Foo foo" and "Foo foos" aren't both declarations?
Dec 22, 2011 at 12:16am
There are 2 constructors in question here:

1) Foo's constructor
2) std::vector's constructor (for your 'shorts' vector)

The #2 constructor is being called once before main starts. This constructor initializes the vector to have zero elements. This can be shown by your Bar() function which undoubtedly prints 0.

The #2 constructor is called because you are creating a vector object. That object is called 'shorts'.

The #1 constructor is never being called in this program because you are not actually creating any Foo objects. You almost are, but you don't. You have a static Foo object in the Foo class, but you never instantiate it, so it is never actually created.

If you want that Foo to be instantiated, you need to add this line:

1
2
3
4
5
class Foo
{ /* ... */ };

std::vector <short> Foo::shorts;  // instantiates Foo::shorts
Foo Foo::foo;  // instantiates Foo::foo  (calls Foo's ctor) 

Last edited on Dec 22, 2011 at 12:17am
Dec 22, 2011 at 12:17am
Ah, I saw only now that you actually had a static Foo object.
However, it's just a declaration, not a definition. You still need to instantiate it as you did with the vector.
Edit: ninja'ed.

And unless you want the vector to be resized every time a Foo instance is created, you should initialize the vector as needed initially:
std::vector<short> Foo::shorts(5);
Last edited on Dec 22, 2011 at 12:20am
Dec 22, 2011 at 12:19am
Pyrius, think about what you're asking.
"static Foo foo" and "Foo foos" aren't both declarations?


My declaration was inside of int main. Your declaration was inside of the class object. You're basically trying to hatch an egg that doesn't have a chicken to hatch from yet.
Dec 22, 2011 at 12:20am
Oh... okay, thanks for explaining.

EDIT: Now the constructor is being called, but later on when I call shorts it has a size of 0.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <vector>

class Foo
{
public:

    Foo();

    static Foo foo;

    static std::vector <short> shorts;
};

Foo Foo::foo;

std::vector <short> Foo::shorts;

Foo::Foo()
{
    shorts.resize(5, 3);
    std::cout << "shorts is of size " << shorts.size() << ".\n\n";
}

int main()
{
    std::cout << "shorts is of size " << Foo::shorts.size() << ".\n";
}


This outputs first "shorts is of size 5," and then "shorts is of size 0"
Last edited on Dec 22, 2011 at 12:36am
Dec 22, 2011 at 12:38am
Static initialization order fiasco.

'shorts' is being constructed AFTER 'foo' is, so first, foo is resizing a vector that has not been constructed yet (!!! very bad!!!), then shorts's constructor initializes it to a size of 0

This results in (at best) a memory leak, but also could corrupt the heap.

This is one reason why statics/globals are a bad idea and should be avoided.
Last edited on Dec 22, 2011 at 12:41am
Dec 22, 2011 at 12:41am
Ah, okay. I can definitely see how resizing a vector before constructing it could be bad :), thanks.
Dec 22, 2011 at 12:53am
Technically this is not 'static initialization order fiasco'. That only applies when your globals are scattered among several compilation units. In this case putting Foo::shorts above Foo::foo would do the trick (I'm not sure, but I think the standard guarantees that inside a compilation unit globals are initialized in the order they are defined). But yes, it's a good idea to avoid statics and globals in general, and it's good to know about the 'static initialization order fiasco' -> http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14
Last edited on Dec 22, 2011 at 4:30pm
Topic archived. No new replies allowed.