What's going on? (classes; templates; inheritance; pointers; static variable)

Hey there,
I have this little program and allready don't know what's going on here...

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
#include <iostream>
#include <vector>

class Base {};
std::vector<Base*> elements;

template <typename T>
class A : public Base
{
public:
    A()
    {
        std::cout << "A-Ctor" << std::endl;
        elements.push_back(&(T::get()));
    }
};
class B : public A<B>
{
public:
    B() { std::cout << "B-Ctor" << std::endl; }
    static B& get() { static B b; return b; }
};

int main(void)
{
    B b;

    std::cout << elements.size() << std::endl;
}

http://cpp.sh/2ku2z
A-Ctor
A-Ctor


I thought it would go like this ...

- B b
| - calls B-Constructor
| | - calls A<B>-Constructor.
| | | - calls std::cout << "A-Ctor" << std::endl;
| | | - calls B::get()
| | | | - calls B-Constructor for the static variable
| | | | | - calls A<B>-Constructor
| | | | | | - calls std::cout << "A-Ctor" << std::endl;
| | | | | | - calls B::get() (no B constructor because of static variable)
| | | | | | - pushes the retreived pointer to the std::vector
| | | | | - calls std::cout << "B-Ctor" << std::endl;
| | | - Inserts the retreived pointer to the std::vector
| | - calls std::cout << "B-Ctor" << std::endl;
- std::cout << elements.size() << std::endl;

... but some reason it just prints A-Ctor twice and then does nothing and the program does not stop.
What did i miss here?


Edit: added a few std::couts to find out more.
For some reason it stops at the second static B b;
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
36
37
#include <iostream>
#include <vector>
#include <memory>

class Base { public: Base() { std::cout << "Base-Ctor" << std::endl; }};
std::vector<Base*> elements;

template <typename T>
class A : public Base
{
public:
    A()
    {
        std::cout << "A-Ctor begin" << std::endl;
        elements.push_back(&(T::get()));
        std::cout << "A-Ctor end" << std::endl;
    }
};
class B : public A<B>
{
public:
    B() { std::cout << "B-Ctor" << std::endl; }
    static B& get() 
    { 
        std::cout << "create static" << std::endl; 
        static B b; 
        std::cout << "return static" << std::endl; 
        return b; 
    }
};

int main(void)
{
    B b;

    std::cout << elements.size() << std::endl;
}

http://cpp.sh/764k
Base-Ctor
A-Ctor begin
create static
Base-Ctor
A-Ctor begin
create static
Last edited on
In B::get, you are creating a static B, effectively constructing another B object.
Afterwards, this static B object calls A constructor (which is why you see two A constructors in the log). This static element's A constructor calls B::get again, leading to ambiguity (is the static object initialized? Will it recursively construct itself?)
I'm pretty sure the behavior is only defined until the second A constructor.
I though static variables are only initialized once?
If that wouldn't be defined behaviours then static variables are pretty much the worst c++ feature...

edit: never mind that (see below)
In functions they are to be only initialized once, that's their purpose (i think)
This works fine...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

int& ifactory()
{
    static int i;
    return i;
}

int main()
{
    int& i1 = ifactory();
    i1 = 10;
    int& i2 = ifactory();
    i2 = 20;
    
    std::cout << i1 << ' '  << i2 << std::endl; // 20 20
}


edit: Oh no...
In my example, the static object's constructor hasn't reached it's end yet so it may be like you say, that the object may or may not be initialized at that moment and the behaviour is undefined :(
Last edited on
That's exactly the issue, referring to itself via another object is undefined behaviour (if the object hasn't beenfully constructed).
Perhaps you should push_back(this)?
The issue is infinite recursion. It crashes with GCC:
http://ideone.com/0KWkhe
terminate called after throwing an instance of '__gnu_cxx::recursive_init_error'
  what():  std::exception
Get rid of your static get function and take SGH's suggestion. A doesn't even have to be a template.
Last edited on
Perhaps you should push_back(this)?
Hooooraaaaaaay!!!!! :DDDDD
yeah, that works perfectly ^.^
Thank you <333

The issue is infinite recursion. It crashes with GCC:
thanks for confirming :)

A doesn't even have to be a template.
Well, it's not the concrete example but in my programm I need it to be a template.
Last edited on
Topic archived. No new replies allowed.